Skip to content

Commit ffab0d7

Browse files
authored
Merge pull request FRRouting#15222 from chiragshah6/fdev2
bgpd:aggr summary-only remove suppressed from evpn
2 parents ac34bad + f345460 commit ffab0d7

8 files changed

+174
-8
lines changed

bgpd/bgp_evpn.c

+77-6
Original file line numberDiff line numberDiff line change
@@ -315,18 +315,13 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn)
315315
* This would be following category:
316316
* Non-imported route,
317317
* Non-EVPN imported route,
318-
* Non Aggregate suppressed route.
319318
*/
320-
bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
319+
bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi)
321320
{
322321
struct bgp_path_info *parent_pi;
323322
struct bgp_table *table;
324323
struct bgp_dest *dest;
325324

326-
/* do not import aggr suppressed routes */
327-
if (bgp_path_suppressed(pi))
328-
return false;
329-
330325
if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra ||
331326
!pi->extra->vrfleak || !pi->extra->vrfleak->parent)
332327
return true;
@@ -344,6 +339,21 @@ bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
344339
return true;
345340
}
346341

342+
/* Flag if the route is injectable into EVPN.
343+
* This would be following category:
344+
* Non-imported route,
345+
* Non-EVPN imported route,
346+
* Non Aggregate suppressed route.
347+
*/
348+
bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
349+
{
350+
/* do not import aggr suppressed routes */
351+
if (bgp_path_suppressed(pi))
352+
return false;
353+
354+
return is_route_injectable_into_evpn_non_supp(pi);
355+
}
356+
347357
/*
348358
* Compare Route Targets.
349359
*/
@@ -7711,3 +7721,64 @@ bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
77117721

77127722
return false;
77137723
}
7724+
7725+
/* Upon aggregate set trigger unimport suppressed routes
7726+
* from EVPN
7727+
*/
7728+
void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi)
7729+
{
7730+
struct bgp_dest *agg_dest, *dest, *top;
7731+
const struct prefix *aggr_p;
7732+
struct bgp_aggregate *bgp_aggregate;
7733+
struct bgp_table *table;
7734+
struct bgp_path_info *pi;
7735+
7736+
if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi))
7737+
return;
7738+
7739+
/* Aggregate-address table walk. */
7740+
table = bgp->rib[afi][safi];
7741+
for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest;
7742+
agg_dest = bgp_route_next(agg_dest)) {
7743+
bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest);
7744+
7745+
if (bgp_aggregate == NULL)
7746+
continue;
7747+
7748+
aggr_p = bgp_dest_get_prefix(agg_dest);
7749+
7750+
/* Look all nodes below the aggregate prefix in
7751+
* global AFI/SAFI table (IPv4/IPv6).
7752+
* Trigger withdrawal (this will be Type-5 routes only)
7753+
* from EVPN Global table.
7754+
*/
7755+
top = bgp_node_get(table, aggr_p);
7756+
for (dest = bgp_node_get(table, aggr_p); dest;
7757+
dest = bgp_route_next_until(dest, top)) {
7758+
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
7759+
7760+
if (dest_p->prefixlen <= aggr_p->prefixlen)
7761+
continue;
7762+
7763+
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
7764+
pi = pi->next) {
7765+
if (pi->sub_type == BGP_ROUTE_AGGREGATE)
7766+
continue;
7767+
7768+
/* Only Suppressed route remove from EVPN */
7769+
if (!bgp_path_suppressed(pi))
7770+
continue;
7771+
7772+
if (BGP_DEBUG(zebra, ZEBRA))
7773+
zlog_debug("%s aggregated %pFX remove suppressed route %pFX",
7774+
__func__, aggr_p, dest_p);
7775+
7776+
if (!is_route_injectable_into_evpn_non_supp(pi))
7777+
continue;
7778+
7779+
bgp_evpn_withdraw_type5_route(bgp, dest_p, afi,
7780+
safi);
7781+
}
7782+
}
7783+
}
7784+
}

bgpd/bgp_evpn.h

+3
Original file line numberDiff line numberDiff line change
@@ -182,5 +182,8 @@ extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi);
182182
extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
183183
struct bgp_path_info *mpinfo);
184184
extern bool is_route_injectable_into_evpn(struct bgp_path_info *pi);
185+
extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi);
186+
extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi,
187+
safi_t safi);
185188

186189
#endif /* _QUAGGA_BGP_EVPN_H */

bgpd/bgp_route.c

+3
Original file line numberDiff line numberDiff line change
@@ -7799,6 +7799,9 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
77997799
lcommunity = lcommunity_dup(aggregate->lcommunity);
78007800
}
78017801

7802+
/* Unimport suppressed routes from EVPN */
7803+
bgp_aggr_supp_withdraw_from_evpn(bgp, afi, safi);
7804+
78027805
bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community,
78037806
ecommunity, lcommunity, atomic_aggregate,
78047807
aggregate);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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}

tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf

+13
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,22 @@ router bgp 65000
1111
advertise-svi-ip
1212
!
1313
router bgp 65000 vrf vrf-red
14+
address-family ipv4 unicast
15+
redistribute static
16+
exit-address-family
1417
!
1518
address-family l2vpn evpn
1619
route-target import *:300
1720
route-target import auto
1821
exit-address-family
1922
!
23+
router bgp 65000 vrf vrf-purple
24+
address-family ipv4 unicast
25+
redistribute static
26+
exit-address-family
27+
!
28+
address-family l2vpn evpn
29+
advertise ipv4 unicast
30+
exit-address-family
31+
32+
!

tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ vrf vrf-red
55
vni 100
66
exit-vrf
77
!
8+
vrf vrf-purple
9+
vni 4000
10+
ip route 10.27.7.0/24 blackhole
11+
ip route 10.27.7.22/32 blackhole
12+
ip route 10.27.7.10/30 blackhole
13+
exit-vrf
814
!
915
interface lo
1016
ip address 10.10.10.10/32

tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py

+70-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf):
9191
pe.run("ip link add name bridge type bridge stp_state 0")
9292
pe.run("ip link set dev bridge type bridge vlan_filtering 1")
9393
pe.run("bridge vlan add vid 1 dev bridge self")
94+
if pe_name == "PE1":
95+
pe.run("ip link set dev bridge address 44:00:00:ff:ff:01")
96+
if pe_name == "PE2":
97+
pe.run("ip link set dev bridge address 44:20:00:ff:ff:01")
9498
pe.run("ip link set dev bridge up")
9599

96100
# setup svi
@@ -113,14 +117,26 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf):
113117
pe.run("bridge vlan add dev vxlan0 vid 1 tunnel_info id 101")
114118
pe.run("ip link set up dev vxlan0")
115119

120+
# VRF creation
121+
pe.run("ip link add vrf-purple type vrf table 1003")
122+
pe.run("ip link set dev vrf-purple up")
123+
if pe_name == "PE1":
124+
pe.run("ip link add vrf-blue type vrf table 1002")
125+
pe.run("ip link set dev vrf-blue up")
126+
pe.run("ip addr add 27.2.0.85/32 dev vrf-blue")
127+
pe.run("ip addr add 27.3.0.85/32 dev vrf-purple")
128+
if pe_name == "PE2":
129+
pe.run("ip link add vrf-blue type vrf table 2400")
130+
pe.run("ip link set dev vrf-blue up")
131+
116132
# setup PE interface
117133
pe.run("ip link set dev {0}-{1} master bridge".format(pe_name, intf))
118134
pe.run("bridge vlan del vid 1 dev {0}-{1}".format(pe_name, intf))
119135
pe.run("bridge vlan del vid 1 untagged pvid dev {0}-{1}".format(pe_name, intf))
120136
pe.run("bridge vlan add vid 1 dev {0}-{1}".format(pe_name, intf))
121137
pe.run("bridge vlan add vid 1 pvid untagged dev {0}-{1}".format(pe_name, intf))
122138

123-
# l3vni 100
139+
# L3VNI 100
124140
pe.run("ip link add vrf-red type vrf table 1400")
125141
pe.run("ip link add link bridge name vlan100 type vlan id 100 protocol 802.1q")
126142
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):
129145
pe.run("bridge vlan add dev vxlan0 vid 100")
130146
pe.run("bridge vlan add dev vxlan0 vid 100 tunnel_info id 100")
131147

148+
# L3VNI 4000
149+
pe.run("ip link add link bridge name vlan400 type vlan id 400 protocol 802.1q")
150+
pe.run("ip link set dev vlan400 master vrf-purple")
151+
pe.run("ip link set dev vlan400 up")
152+
pe.run("bridge vlan add vid 400 dev bridge self")
153+
pe.run("bridge vlan add dev vxlan0 vid 400")
154+
pe.run("bridge vlan add dev vxlan0 vid 400 tunnel_info id 4000")
155+
132156
# add a vrf for testing DVNI
133157
if pe_name == "PE2":
134-
pe.run("ip link add vrf-blue type vrf table 2400")
135158
pe.run("ip link add link bridge name vlan300 type vlan id 300 protocol 802.1q")
136159
pe.run("ip link set dev vlan300 master vrf-blue")
137160
pe.run("ip link set dev vlan300 up")
@@ -199,6 +222,14 @@ def show_vni_json_elide_ifindex(pe, vni, expected):
199222
return topotest.json_cmp(output_json, expected)
200223

201224

225+
def show_bgp_l2vpn_evpn_route_type_prefix_json(pe, expected):
226+
output_json = pe.vtysh_cmd(
227+
"show bgp l2vpn evpn route type prefix json", isjson=True
228+
)
229+
230+
return topotest.json_cmp(output_json, expected)
231+
232+
202233
def check_vni_macs_present(tgen, router, vni, maclist):
203234
result = router.vtysh_cmd("show evpn mac vni {} json".format(vni), isjson=True)
204235
for rname, ifname in maclist:
@@ -331,6 +362,7 @@ def mac_test_local_remote(local, remote):
331362
remote_output_json = json.loads(remote_output)
332363
local_output_vni_json = json.loads(local_output_vni)
333364

365+
# breakpoint()
334366
for vni in local_output_json:
335367
if vni not in remote_output_json:
336368
continue
@@ -542,6 +574,42 @@ def test_dvni():
542574
# tgen.mininet_cli()
543575

544576

577+
def test_pe_advertise_aggr_evpn_route():
578+
"BGP advertise aggregated Type-5 prefix route"
579+
580+
tgen = get_topogen()
581+
# Don't run this test if we have any failure.
582+
if tgen.routers_have_failure():
583+
pytest.skip(tgen.errors)
584+
585+
logger.info("Checking BGP EVPN route contains non-aggregate prefixes")
586+
pe1 = tgen.gears["PE1"]
587+
json_file = "{}/{}/bgp.evpn.route.prefix.before.json".format(CWD, pe1.name)
588+
expected = json.loads(open(json_file).read())
589+
590+
test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected)
591+
_, result = topotest.run_and_expect(test_func, None, count=45, wait=1)
592+
assertmsg = '"{}" JSON output mismatches'.format(pe1.name)
593+
assert result is None, assertmsg
594+
595+
logger.info("Configure BGP aggregate-address summary-only under ipv4-unicast")
596+
pe1.cmd(
597+
'vtysh -c "config t" -c "router bgp 65000 vrf vrf-purple" '
598+
+ ' -c "address-family ipv4 unicast" '
599+
+ ' -c "aggregate-address 10.27.0.0/16 summary-only" '
600+
)
601+
602+
logger.info("Checking BGP EVPN route contains aggregated prefix")
603+
pe1 = tgen.gears["PE1"]
604+
json_file = "{}/{}/bgp.evpn.route.prefix.after.json".format(CWD, pe1.name)
605+
expected = json.loads(open(json_file).read())
606+
607+
test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected)
608+
_, result = topotest.run_and_expect(test_func, None, count=45, wait=1)
609+
assertmsg = '"{}" JSON output mismatches'.format(pe1.name)
610+
assert result is None, assertmsg
611+
612+
545613
def test_memory_leak():
546614
"Run the memory leak test and report results."
547615
tgen = get_topogen()

0 commit comments

Comments
 (0)