diff options
| -rw-r--r-- | bgpd/bgp_evpn.c | 83 | ||||
| -rw-r--r-- | bgpd/bgp_evpn.h | 3 | ||||
| -rw-r--r-- | bgpd/bgp_nht.c | 17 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 3 | ||||
| -rw-r--r-- | doc/user/basic.rst | 4 | ||||
| -rw-r--r-- | ospfd/ospf_asbr.c | 3 | ||||
| -rw-r--r-- | tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json | 1 | ||||
| -rw-r--r-- | tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json | 1 | ||||
| -rw-r--r-- | tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf | 13 | ||||
| -rw-r--r-- | tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf | 6 | ||||
| -rwxr-xr-x | tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py | 72 | ||||
| -rwxr-xr-x | tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py | 1 | ||||
| -rw-r--r-- | tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json | 3 | ||||
| -rw-r--r-- | tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json | 3 | ||||
| -rw-r--r-- | yang/frr-zebra.yang | 12 | ||||
| -rw-r--r-- | zebra/dplane_fpm_nl.c | 8 | ||||
| -rw-r--r-- | zebra/zebra_nb.c | 6 | ||||
| -rw-r--r-- | zebra/zebra_nb.h | 1 | ||||
| -rw-r--r-- | zebra/zebra_nb_state.c | 64 |
19 files changed, 273 insertions, 31 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1a4364bb74..a846484f0e 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -315,18 +315,13 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn) * This would be following category: * Non-imported route, * Non-EVPN imported route, - * Non Aggregate suppressed route. */ -bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi) { struct bgp_path_info *parent_pi; struct bgp_table *table; struct bgp_dest *dest; - /* do not import aggr suppressed routes */ - if (bgp_path_suppressed(pi)) - return false; - if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || !pi->extra->vrfleak || !pi->extra->vrfleak->parent) return true; @@ -344,6 +339,21 @@ bool is_route_injectable_into_evpn(struct bgp_path_info *pi) return true; } +/* Flag if the route is injectable into EVPN. + * This would be following category: + * Non-imported route, + * Non-EVPN imported route, + * Non Aggregate suppressed route. + */ +bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +{ + /* do not import aggr suppressed routes */ + if (bgp_path_suppressed(pi)) + return false; + + return is_route_injectable_into_evpn_non_supp(pi); +} + /* * Compare Route Targets. */ @@ -7711,3 +7721,64 @@ bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, return false; } + +/* Upon aggregate set trigger unimport suppressed routes + * from EVPN + */ +void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_dest *agg_dest, *dest, *top; + const struct prefix *aggr_p; + struct bgp_aggregate *bgp_aggregate; + struct bgp_table *table; + struct bgp_path_info *pi; + + if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi)) + return; + + /* Aggregate-address table walk. */ + table = bgp->rib[afi][safi]; + for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest; + agg_dest = bgp_route_next(agg_dest)) { + bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest); + + if (bgp_aggregate == NULL) + continue; + + aggr_p = bgp_dest_get_prefix(agg_dest); + + /* Look all nodes below the aggregate prefix in + * global AFI/SAFI table (IPv4/IPv6). + * Trigger withdrawal (this will be Type-5 routes only) + * from EVPN Global table. + */ + top = bgp_node_get(table, aggr_p); + for (dest = bgp_node_get(table, aggr_p); dest; + dest = bgp_route_next_until(dest, top)) { + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + + if (dest_p->prefixlen <= aggr_p->prefixlen) + continue; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + continue; + + /* Only Suppressed route remove from EVPN */ + if (!bgp_path_suppressed(pi)) + continue; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s aggregated %pFX remove suppressed route %pFX", + __func__, aggr_p, dest_p); + + if (!is_route_injectable_into_evpn_non_supp(pi)) + continue; + + bgp_evpn_withdraw_type5_route(bgp, dest_p, afi, + safi); + } + } + } +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 8403897587..c641a64f62 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -182,5 +182,8 @@ extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi); extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, struct bgp_path_info *mpinfo); extern bool is_route_injectable_into_evpn(struct bgp_path_info *pi); +extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi); +extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, + safi_t safi); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 884fabf077..fa566f0433 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -1068,18 +1068,19 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL - && (IN6_IS_ADDR_UNSPECIFIED( - &pi->attr->mp_nexthop_global) - || IN6_IS_ADDR_LINKLOCAL( - &pi->attr->mp_nexthop_global))) + if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && + (IN6_IS_ADDR_UNSPECIFIED( + &pi->attr->mp_nexthop_global) || + IN6_IS_ADDR_LINKLOCAL(&pi->attr->mp_nexthop_global))) p->u.prefix6 = pi->attr->mp_nexthop_local; /* If we receive MR_REACH with (GA)::(LL) * then check for route-map to choose GA or LL */ - else if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + else if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (CHECK_FLAG(pi->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL)) p->u.prefix6 = diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 45951e9ea8..520185e60f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7799,6 +7799,9 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, lcommunity = lcommunity_dup(aggregate->lcommunity); } + /* Unimport suppressed routes from EVPN */ + bgp_aggr_supp_withdraw_from_evpn(bgp, afi, safi); + bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 7f9027679f..5fdd1887fa 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -206,7 +206,7 @@ Basic Config Commands enabled log destinations. The note that logging includes full command lines, including passwords. If the daemon startup option `--command-log-always` is used to start the daemon then this command is turned on by default - and cannot be turned off and the [no] form of the command is dissallowed. + and cannot be turned off and the [no] form of the command is disallowed. .. clicmd:: log filtered-file [FILENAME [LEVEL]] @@ -769,7 +769,7 @@ These options apply to all |PACKAGE_NAME| daemons. .. option:: --command-log-always Cause the daemon to always log commands entered to the specified log file. - This also makes the `no log commands` command dissallowed. Enabling this + This also makes the `no log commands` command disallowed. Enabling this is suggested if you have need to track what the operator is doing on this router. diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 5baad1754d..9b62f36d7a 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -110,7 +110,8 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance, new = rn->info; if ((new->ifindex == ifindex) && (new->nexthop.s_addr == nexthop.s_addr) - && (new->tag == tag)) { + && (new->tag == tag) + && (new->metric == metric)) { route_unlock_node(rn); return NULL; /* NULL => no LSA to refresh */ } diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json new file mode 100644 index 0000000000..0b5b1a1e2b --- /dev/null +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json @@ -0,0 +1 @@ +{"27.3.0.85:3":{"rd":"27.3.0.85:3","[5]:[0]:[16]:[10.27.0.0]":{"prefix":"[5]:[0]:[16]:[10.27.0.0]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":16,"ip":"10.27.0.0","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]}},"30.0.0.3:2":{"rd":"30.0.0.3:2","[5]:[0]:[32]:[4.4.4.1]":{"prefix":"[5]:[0]:[32]:[4.4.4.1]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"internal","routeType":5,"ethTag":0,"ipLen":32,"ip":"4.4.4.1","metric":0,"locPrf":100,"weight":0,"peerId":"10.30.30.30","path":"","origin":"incomplete","extendedCommunity":{"string":"RT:65000:300 ET:8 Rmac:44:20:00:ff:ff:01"},"nexthops":[{"ip":"10.30.30.30","hostname":"PE2","afi":"ipv4","used":true}]}]]}},"numPrefix":2,"numPaths":2} diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json new file mode 100644 index 0000000000..67417b5986 --- /dev/null +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json @@ -0,0 +1 @@ +{"27.3.0.85:3":{"rd":"27.3.0.85:3","[5]:[0]:[24]:[10.27.7.0]":{"prefix":"[5]:[0]:[24]:[10.27.7.0]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":24,"ip":"10.27.7.0","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]},"[5]:[0]:[30]:[10.27.7.8]":{"prefix":"[5]:[0]:[30]:[10.27.7.8]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":30,"ip":"10.27.7.8","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]},"[5]:[0]:[32]:[10.27.7.22]":{"prefix":"[5]:[0]:[32]:[10.27.7.22]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":32,"ip":"10.27.7.22","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]}},"30.0.0.3:2":{"rd":"30.0.0.3:2","[5]:[0]:[32]:[4.4.4.1]":{"prefix":"[5]:[0]:[32]:[4.4.4.1]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"internal","routeType":5,"ethTag":0,"ipLen":32,"ip":"4.4.4.1","metric":0,"locPrf":100,"weight":0,"peerId":"10.30.30.30","path":"","origin":"incomplete","extendedCommunity":{"string":"RT:65000:300 ET:8 Rmac:44:20:00:ff:ff:01"},"nexthops":[{"ip":"10.30.30.30","hostname":"PE2","afi":"ipv4","used":true}]}]]}},"numPrefix":4,"numPaths":4} diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf index 9fb2bd6835..b58219ad8e 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf @@ -11,9 +11,22 @@ router bgp 65000 advertise-svi-ip ! router bgp 65000 vrf vrf-red + address-family ipv4 unicast + redistribute static + exit-address-family ! address-family l2vpn evpn route-target import *:300 route-target import auto exit-address-family ! +router bgp 65000 vrf vrf-purple + address-family ipv4 unicast + redistribute static + exit-address-family + ! + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family + +! diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf index 8c6cf3e6d4..cea60a8b1e 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf @@ -5,6 +5,12 @@ vrf vrf-red vni 100 exit-vrf ! +vrf vrf-purple + vni 4000 + ip route 10.27.7.0/24 blackhole + ip route 10.27.7.22/32 blackhole + ip route 10.27.7.10/30 blackhole +exit-vrf ! interface lo ip address 10.10.10.10/32 diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py index 65c0c3532a..fd75c34ebf 100755 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py @@ -91,6 +91,10 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("ip link add name bridge type bridge stp_state 0") pe.run("ip link set dev bridge type bridge vlan_filtering 1") pe.run("bridge vlan add vid 1 dev bridge self") + if pe_name == "PE1": + pe.run("ip link set dev bridge address 44:00:00:ff:ff:01") + if pe_name == "PE2": + pe.run("ip link set dev bridge address 44:20:00:ff:ff:01") pe.run("ip link set dev bridge up") # setup svi @@ -113,6 +117,18 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add dev vxlan0 vid 1 tunnel_info id 101") pe.run("ip link set up dev vxlan0") + # VRF creation + pe.run("ip link add vrf-purple type vrf table 1003") + pe.run("ip link set dev vrf-purple up") + if pe_name == "PE1": + pe.run("ip link add vrf-blue type vrf table 1002") + pe.run("ip link set dev vrf-blue up") + pe.run("ip addr add 27.2.0.85/32 dev vrf-blue") + pe.run("ip addr add 27.3.0.85/32 dev vrf-purple") + if pe_name == "PE2": + pe.run("ip link add vrf-blue type vrf table 2400") + pe.run("ip link set dev vrf-blue up") + # setup PE interface pe.run("ip link set dev {0}-{1} master bridge".format(pe_name, intf)) pe.run("bridge vlan del vid 1 dev {0}-{1}".format(pe_name, intf)) @@ -120,7 +136,7 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add vid 1 dev {0}-{1}".format(pe_name, intf)) pe.run("bridge vlan add vid 1 pvid untagged dev {0}-{1}".format(pe_name, intf)) - # l3vni 100 + # L3VNI 100 pe.run("ip link add vrf-red type vrf table 1400") pe.run("ip link add link bridge name vlan100 type vlan id 100 protocol 802.1q") pe.run("ip link set dev vlan100 master vrf-blue") @@ -129,9 +145,16 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add dev vxlan0 vid 100") pe.run("bridge vlan add dev vxlan0 vid 100 tunnel_info id 100") + # L3VNI 4000 + pe.run("ip link add link bridge name vlan400 type vlan id 400 protocol 802.1q") + pe.run("ip link set dev vlan400 master vrf-purple") + pe.run("ip link set dev vlan400 up") + pe.run("bridge vlan add vid 400 dev bridge self") + pe.run("bridge vlan add dev vxlan0 vid 400") + pe.run("bridge vlan add dev vxlan0 vid 400 tunnel_info id 4000") + # add a vrf for testing DVNI if pe_name == "PE2": - pe.run("ip link add vrf-blue type vrf table 2400") pe.run("ip link add link bridge name vlan300 type vlan id 300 protocol 802.1q") pe.run("ip link set dev vlan300 master vrf-blue") pe.run("ip link set dev vlan300 up") @@ -199,6 +222,14 @@ def show_vni_json_elide_ifindex(pe, vni, expected): return topotest.json_cmp(output_json, expected) +def show_bgp_l2vpn_evpn_route_type_prefix_json(pe, expected): + output_json = pe.vtysh_cmd( + "show bgp l2vpn evpn route type prefix json", isjson=True + ) + + return topotest.json_cmp(output_json, expected) + + def check_vni_macs_present(tgen, router, vni, maclist): result = router.vtysh_cmd("show evpn mac vni {} json".format(vni), isjson=True) for rname, ifname in maclist: @@ -331,6 +362,7 @@ def mac_test_local_remote(local, remote): remote_output_json = json.loads(remote_output) local_output_vni_json = json.loads(local_output_vni) + # breakpoint() for vni in local_output_json: if vni not in remote_output_json: continue @@ -542,6 +574,42 @@ def test_dvni(): # tgen.mininet_cli() +def test_pe_advertise_aggr_evpn_route(): + "BGP advertise aggregated Type-5 prefix route" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking BGP EVPN route contains non-aggregate prefixes") + pe1 = tgen.gears["PE1"] + json_file = "{}/{}/bgp.evpn.route.prefix.before.json".format(CWD, pe1.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected) + _, result = topotest.run_and_expect(test_func, None, count=45, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(pe1.name) + assert result is None, assertmsg + + logger.info("Configure BGP aggregate-address summary-only under ipv4-unicast") + pe1.cmd( + 'vtysh -c "config t" -c "router bgp 65000 vrf vrf-purple" ' + + ' -c "address-family ipv4 unicast" ' + + ' -c "aggregate-address 10.27.0.0/16 summary-only" ' + ) + + logger.info("Checking BGP EVPN route contains aggregated prefix") + pe1 = tgen.gears["PE1"] + json_file = "{}/{}/bgp.evpn.route.prefix.after.json".format(CWD, pe1.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected) + _, result = topotest.run_and_expect(test_func, None, count=45, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(pe1.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py b/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py index 9239be9221..340df71a19 100755 --- a/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py @@ -103,7 +103,6 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/setup_vrfs".format(CWD)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json index f04e3a55e1..04591b6e29 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json @@ -14,7 +14,8 @@ "frr-zebra:zebra": { "state": { "up-count": 0, - "down-count": 0 + "down-count": 0, + "zif-type": "zif-veth" } } } diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json index 84ad82c058..c770db49b1 100644 --- a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json @@ -25,7 +25,8 @@ }, "state": { "up-count": 0, - "down-count": 0 + "down-count": 0, + "zif-type": "zif-veth" } } } diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index c338a23af0..f1a69068c3 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -145,12 +145,6 @@ module frr-zebra { "Zebra interface type bond."; } - identity zif-bond-slave { - base zebra-interface-type; - description - "Zebra interface type bond slave."; - } - identity zif-macvlan { base zebra-interface-type; description @@ -2733,6 +2727,12 @@ module frr-zebra { description "The VNI multicast group for BUM traffic."; } + + leaf bond { + type frr-interface:interface-ref; + description + "The bond interface this interface belongs to."; + } } } } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 3e7e84edd2..245b799a91 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1465,8 +1465,14 @@ static void fpm_process_queue(struct event *t) uint64_t processed_contexts = 0; while (true) { + size_t writeable_amount; + + frr_with_mutex (&fnc->obuf_mutex) { + writeable_amount = STREAM_WRITEABLE(fnc->obuf); + } + /* No space available yet. */ - if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE) { + if (writeable_amount < NL_PKT_BUF_SIZE) { no_bufs = true; break; } diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index e1ca5ec19b..eee9323082 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -803,6 +803,12 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/bond", + .cbs = { + .get_elem = lib_interface_zebra_state_bond_get_elem, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/router-id", .cbs = { .modify = lib_vrf_zebra_router_id_modify, diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index d7cf5f4040..b40ed68229 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -285,6 +285,7 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem( struct nb_cb_get_elem_args *args); struct yang_data *lib_interface_zebra_state_mcast_group_get_elem( struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args); int lib_vrf_zebra_router_id_modify(struct nb_cb_modify_args *args); int lib_vrf_zebra_router_id_destroy(struct nb_cb_destroy_args *args); int lib_vrf_zebra_ipv6_router_id_modify(struct nb_cb_modify_args *args); diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index 00df9bfc55..464c0be707 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -49,8 +49,46 @@ lib_interface_zebra_state_down_count_get_elem(struct nb_cb_get_elem_args *args) struct yang_data * lib_interface_zebra_state_zif_type_get_elem(struct nb_cb_get_elem_args *args) { - /* TODO: implement me. */ - return NULL; + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + const char *type = NULL; + + zebra_if = ifp->info; + + switch (zebra_if->zif_type) { + case ZEBRA_IF_OTHER: + type = "frr-zebra:zif-other"; + break; + case ZEBRA_IF_VXLAN: + type = "frr-zebra:zif-vxlan"; + break; + case ZEBRA_IF_VRF: + type = "frr-zebra:zif-vrf"; + break; + case ZEBRA_IF_BRIDGE: + type = "frr-zebra:zif-bridge"; + break; + case ZEBRA_IF_VLAN: + type = "frr-zebra:zif-vlan"; + break; + case ZEBRA_IF_MACVLAN: + type = "frr-zebra:zif-macvlan"; + break; + case ZEBRA_IF_VETH: + type = "frr-zebra:zif-veth"; + break; + case ZEBRA_IF_BOND: + type = "frr-zebra:zif-bond"; + break; + case ZEBRA_IF_GRE: + type = "frr-zebra:zif-gre"; + break; + } + + if (!type) + return NULL; + + return yang_data_new_string(args->xpath, type); } /* @@ -145,6 +183,28 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args) return yang_data_new_ipv4(args->xpath, &vni->mcast_grp); } +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/bond + */ +struct yang_data * +lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + struct interface *bond; + + if (!IS_ZEBRA_IF_BOND_SLAVE(ifp)) + return NULL; + + zebra_if = ifp->info; + bond = zebra_if->bondslave_info.bond_if; + + if (!bond) + return NULL; + + return yang_data_new_string(args->xpath, bond->name); +} + const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) { struct vrf *vrf = (struct vrf *)args->parent_list_entry; |
