summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c83
-rw-r--r--bgpd/bgp_evpn.h3
-rw-r--r--bgpd/bgp_nht.c17
-rw-r--r--bgpd/bgp_route.c3
-rw-r--r--doc/user/basic.rst4
-rw-r--r--ospfd/ospf_asbr.c3
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf6
-rwxr-xr-xtests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py72
-rwxr-xr-xtests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py1
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json3
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json3
-rw-r--r--yang/frr-zebra.yang12
-rw-r--r--zebra/dplane_fpm_nl.c8
-rw-r--r--zebra/zebra_nb.c6
-rw-r--r--zebra/zebra_nb.h1
-rw-r--r--zebra/zebra_nb_state.c64
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;