Skip to content

Commit e746985

Browse files
committed
bgpd: fix export prefixes when rt extcomm set by route-map
When exporting BGP prefixes, it is necessary to configure the route target extended communities with the following command: > rt vpn export <RouteTarget> But the customer may need to configure the route-target to apply to bgp updates, solely based on a route-map criterium. by using the below route-map configured like that: > route-map vpn export <routemapname> Fix this by allowing to export bgp updates based on the presence of route-targets on either route-map or vpn configured rt. the exportation process is stopped if no route target is available in the ecommunity list. Fixes: ddb5b48 ("bgpd: vpn-vrf route leaking") Signed-off-by: Philippe Guibert <[email protected]>
1 parent 7243e9d commit e746985

File tree

6 files changed

+92
-17
lines changed

6 files changed

+92
-17
lines changed

bgpd/bgp_ecommunity.c

+28
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,34 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
10421042
return len;
10431043
}
10441044

1045+
bool ecommunity_has_route_target(struct ecommunity *ecom)
1046+
{
1047+
uint32_t i;
1048+
uint8_t *pnt;
1049+
uint8_t type = 0;
1050+
uint8_t sub_type = 0;
1051+
1052+
if (!ecom)
1053+
return false;
1054+
for (i = 0; i < ecom->size; i++) {
1055+
/* Retrieve value field */
1056+
pnt = ecom->val + (i * ecom->unit_size);
1057+
1058+
/* High-order octet is the type */
1059+
type = *pnt++;
1060+
1061+
if (type == ECOMMUNITY_ENCODE_AS ||
1062+
type == ECOMMUNITY_ENCODE_IP ||
1063+
type == ECOMMUNITY_ENCODE_AS4) {
1064+
/* Low-order octet of type. */
1065+
sub_type = *pnt++;
1066+
if (sub_type == ECOMMUNITY_ROUTE_TARGET)
1067+
return true;
1068+
}
1069+
}
1070+
return false;
1071+
}
1072+
10451073
/* Convert extended community attribute to string.
10461074
* Due to historical reason of industry standard implementation, there
10471075
* are three types of format:

bgpd/bgp_ecommunity.h

+1
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ extern struct ecommunity *ecommunity_str2com(const char *, int, int);
341341
extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type,
342342
int keyword_included);
343343
extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
344+
extern bool ecommunity_has_route_target(struct ecommunity *ecom);
344345
extern void ecommunity_strfree(char **s);
345346
extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);
346347
extern bool ecommunity_match(const struct ecommunity *,

bgpd/bgp_mplsvpn.c

+25-12
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi)
300300
return;
301301
}
302302

303-
if (vpn_leak_to_vpn_active(bgp, afi, NULL)) {
303+
if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) {
304304
label = bgp->vpn_policy[afi].tovpn_label;
305305
}
306306

@@ -1533,6 +1533,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
15331533
struct bgp_dest *bn;
15341534
const char *debugmsg;
15351535
int nexthop_self_flag = 0;
1536+
struct ecommunity *old_ecom;
1537+
struct ecommunity *new_ecom = NULL;
1538+
struct ecommunity *rtlist_ecom;
15361539

15371540
if (debug)
15381541
zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty);
@@ -1560,7 +1563,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
15601563
if (!is_route_injectable_into_vpn(path_vrf))
15611564
return;
15621565

1563-
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
1566+
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, false)) {
15641567
if (debug)
15651568
zlog_debug("%s: %s skipping: %s", __func__,
15661569
from_bgp->name, debugmsg);
@@ -1609,27 +1612,37 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
16091612
/*
16101613
* Add the vpn-policy rt-list
16111614
*/
1612-
struct ecommunity *old_ecom;
1613-
struct ecommunity *new_ecom;
16141615

16151616
/* Export with the 'from' instance's export RTs. */
16161617
/* If doing VRF-to-VRF leaking, strip existing RTs first. */
16171618
old_ecom = bgp_attr_get_ecommunity(&static_attr);
1619+
rtlist_ecom = from_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN];
16181620
if (old_ecom) {
16191621
new_ecom = ecommunity_dup(old_ecom);
16201622
if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
16211623
BGP_CONFIG_VRF_TO_VRF_EXPORT))
16221624
ecommunity_strip_rts(new_ecom);
1623-
new_ecom = ecommunity_merge(
1624-
new_ecom, from_bgp->vpn_policy[afi]
1625-
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
1625+
if (rtlist_ecom)
1626+
new_ecom = ecommunity_merge(new_ecom, rtlist_ecom);
16261627
if (!old_ecom->refcnt)
16271628
ecommunity_free(&old_ecom);
1629+
} else if (rtlist_ecom) {
1630+
new_ecom = ecommunity_dup(rtlist_ecom);
16281631
} else {
1629-
new_ecom = ecommunity_dup(
1630-
from_bgp->vpn_policy[afi]
1631-
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
1632+
if (debug)
1633+
zlog_debug("%s: %s skipping: waiting for a non empty export rt list.",
1634+
__func__, from_bgp->name_pretty);
1635+
return;
16321636
}
1637+
1638+
if (!ecommunity_has_route_target(new_ecom)) {
1639+
ecommunity_free(&new_ecom);
1640+
if (debug)
1641+
zlog_debug("%s: %s skipping: waiting for a valid export rt list.",
1642+
__func__, from_bgp->name_pretty);
1643+
return;
1644+
}
1645+
16331646
bgp_attr_set_ecommunity(&static_attr, new_ecom);
16341647

16351648
if (debug && bgp_attr_get_ecommunity(&static_attr)) {
@@ -1885,7 +1898,7 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
18851898
if (!is_route_injectable_into_vpn(path_vrf))
18861899
return;
18871900

1888-
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
1901+
if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, true)) {
18891902
if (debug)
18901903
zlog_debug("%s: skipping: %s", __func__, debugmsg);
18911904
return;
@@ -2666,7 +2679,7 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
26662679
edir = BGP_VPN_POLICY_DIR_TOVPN;
26672680

26682681
for (afi = 0; afi < AFI_MAX; ++afi) {
2669-
if (!vpn_leak_to_vpn_active(bgp, afi, NULL))
2682+
if (!vpn_leak_to_vpn_active(bgp, afi, NULL, false))
26702683
continue;
26712684

26722685
if (withdraw) {

bgpd/bgp_mplsvpn.h

+18-5
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ static inline bool is_bgp_vrf_mplsvpn(struct bgp *bgp)
113113
}
114114

115115
static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
116-
const char **pmsg)
116+
const char **pmsg,
117+
bool ignore_export_rt_list)
117118
{
118119
if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF
119120
&& bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
@@ -133,8 +134,21 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
133134
return 0;
134135
}
135136

136-
/* Is there an RT list set? */
137-
if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) {
137+
/* Before performing withdrawal, VPN activation is checked; however,
138+
* when the route-map modifies the export route-target (RT) list, it
139+
* becomes challenging to determine if VPN prefixes were previously
140+
* present, or not. The 'ignore_export_rt_list' parameter will be
141+
* used to force the withdraw operation by not checking the possible
142+
* route-map changes.
143+
* Of the 'ignore_export_rt_list' is set to false, check the following:
144+
* - Is there an RT list set?
145+
* - Is there a route-map that sets RT communities
146+
*/
147+
if (!ignore_export_rt_list &&
148+
!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] &&
149+
(!bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] ||
150+
!bgp_route_map_has_extcommunity_rt(
151+
bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]))) {
138152
if (pmsg)
139153
*pmsg = "rtlist tovpn not defined";
140154
return 0;
@@ -246,8 +260,7 @@ static inline void vpn_leak_prechange(enum vpn_policy_direction direction,
246260
vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi);
247261
}
248262
if ((direction == BGP_VPN_POLICY_DIR_TOVPN) &&
249-
vpn_leak_to_vpn_active(bgp_vrf, afi, NULL)) {
250-
263+
vpn_leak_to_vpn_active(bgp_vrf, afi, NULL, true)) {
251264
vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi);
252265
}
253266
}

bgpd/bgp_routemap.c

+18
Original file line numberDiff line numberDiff line change
@@ -4743,6 +4743,24 @@ static void bgp_route_map_delete(const char *rmap_name)
47434743
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED);
47444744
}
47454745

4746+
bool bgp_route_map_has_extcommunity_rt(const struct route_map *map)
4747+
{
4748+
struct route_map_index *index = NULL;
4749+
struct route_map_rule *set = NULL;
4750+
4751+
assert(map);
4752+
4753+
for (index = map->head; index; index = index->next) {
4754+
for (set = index->set_list.head; set; set = set->next) {
4755+
if (set->cmd && set->cmd->str &&
4756+
(strmatch(set->cmd->str, "extcommunity rt") ||
4757+
strmatch(set->cmd->str, "extended-comm-list")))
4758+
return true;
4759+
}
4760+
}
4761+
return false;
4762+
}
4763+
47464764
static void bgp_route_map_event(const char *rmap_name)
47474765
{
47484766
if (route_map_mark_updated(rmap_name) == 0)

bgpd/bgpd.h

+2
Original file line numberDiff line numberDiff line change
@@ -2446,6 +2446,8 @@ extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp);
24462446

24472447
extern void bgp_route_map_terminate(void);
24482448

2449+
extern bool bgp_route_map_has_extcommunity_rt(const struct route_map *map);
2450+
24492451
extern int peer_cmp(struct peer *p1, struct peer *p2);
24502452

24512453
extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi,

0 commit comments

Comments
 (0)