Skip to content

Commit

Permalink
bgpd: route-map to filter received EVPN routes based on VNI does not …
Browse files Browse the repository at this point in the history
…work

Issue1: When "neighbor X.X.X.X route-map RM-VNI-FILTER in" is configured under evpn address-family,
all the received routes are dropped regardless of whether the route has a matching vni or not.

Issue2: Routes with 2 labels are not filtered correctly

Issue3: Interpreting the label based on tunnel type, vxlan was not done correctly.
Vxlan label has 24 bits, whereas, MPLS label is 20 bits long

Fix1: The handler bgp_update() that services the received route ignored the route's label while deciding whether to filter it or not. As part of the fix, the handler now uses the label info to make the decision about whether to filter the route or not.

Fix2: route_match_vni() now tries to match both the labels within the route, not just the one.

Fix3:tunnel_type from the extended community is now used to determine how to interpret he label bits (24 bits for vxlan)

Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
  • Loading branch information
lkrishnamoor committed Apr 25, 2019
1 parent c5dafdb commit b513aaa
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 15 deletions.
3 changes: 3 additions & 0 deletions bgpd/bgp_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)

}

/* Get the tunnel type from encap extended community */
(void) bgp_attr_extcom_tunnel_type(attr, &attr->encap_tunneltype);

return BGP_ATTR_PARSE_PROCEED;
}

Expand Down
29 changes: 29 additions & 0 deletions bgpd/bgp_attr_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,35 @@ void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag)
}
}

/*
* Fetch and return tunnel type if present.
*/
bool bgp_attr_extcom_tunnel_type(struct attr *attr, uint16_t *tunnel_type)
{
struct ecommunity *ecom;
int i;

ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return false;

for (i = 0; i < ecom->size; i++) {
uint8_t *pnt;
uint8_t type, sub_type;

pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
type = pnt[0];
sub_type = pnt[1];
if (!(type == ECOMMUNITY_ENCODE_OPAQUE &&
sub_type == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP))
continue;
*tunnel_type = ((pnt[6] << 8) | pnt[7]);
return true;
}

return false;
}

/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
struct prefix *dst)
Expand Down
3 changes: 2 additions & 1 deletion bgpd/bgp_attr_evpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,6 @@ extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
extern uint8_t bgp_attr_default_gw(struct attr *attr);

extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag);

extern bool bgp_attr_extcom_tunnel_type(struct attr *attr,
uint16_t *tunnel_type);
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
8 changes: 8 additions & 0 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -5841,6 +5841,14 @@ void bgp_evpn_flood_control_change(struct bgp *bgp)
hash_iterate(bgp->vnihash, delete_withdraw_type3, bgp);
}

bool is_evpn_tunnel_type_vxlan(afi_t afi, safi_t safi, uint16_t tunnel_type)
{
if (afi == AFI_L2VPN && safi == SAFI_EVPN &&
tunnel_type == BGP_ENCAP_TYPE_VXLAN)
return true;
return false;
}

/*
* Cleanup EVPN information on disable - Need to delete and withdraw
* EVPN routes from peers.
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_evpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern void bgp_evpn_flood_control_change(struct bgp *bgp);
extern bool is_evpn_tunnel_type_vxlan(afi_t afi, safi_t safi,
uint16_t tunnel_type);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);
Expand Down
27 changes: 18 additions & 9 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1198,10 +1198,12 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr)

static int bgp_input_modifier(struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
const char *rmap_name)
const char *rmap_name, mpls_label_t *label,
uint32_t num_labels)
{
struct bgp_filter *filter;
struct bgp_path_info rmap_path;
struct bgp_path_info rmap_path = { 0 };
struct bgp_path_info_extra extra = { 0 };
route_map_result_t ret;
struct route_map *rmap = NULL;

Expand Down Expand Up @@ -1245,6 +1247,11 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
/* Duplicate current value to new strucutre for modification. */
rmap_path.peer = peer;
rmap_path.attr = attr;
rmap_path.extra = &extra;
extra.num_labels = num_labels;
if (label && num_labels && num_labels <= BGP_MAX_LABELS)
memcpy(extra.label, label,
num_labels * sizeof(mpls_label_t));

SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN);

Expand Down Expand Up @@ -2983,8 +2990,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
bgp = peer->bgp;
rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
/* TODO: Check to see if we can get rid of "is_valid_label" */
if (afi == AFI_L2VPN && safi == SAFI_EVPN)
has_valid_label = (num_labels > 0) ? 1 : 0;
if (is_evpn_tunnel_type_vxlan(afi, safi, attr->encap_tunneltype))
has_valid_label = 1;
else
has_valid_label = bgp_is_valid_label(label);

Expand Down Expand Up @@ -3064,8 +3071,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
* commands, so we need bgp_attr_flush in the error paths, until we
* intern
* the attr (which takes over the memory references) */
if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL)
== RMAP_DENY) {
if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL,
label, num_labels) == RMAP_DENY) {
reason = "route-map;";
bgp_attr_flush(&new_attr);
goto filtered;
Expand Down Expand Up @@ -3288,7 +3295,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
num_labels * sizeof(mpls_label_t));
extra->num_labels = num_labels;
}
if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
if (!(is_evpn_tunnel_type_vxlan(afi, safi,
attr->encap_tunneltype)))
bgp_set_valid_label(&extra->label[0]);
}

Expand Down Expand Up @@ -3461,7 +3469,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
num_labels * sizeof(mpls_label_t));
extra->num_labels = num_labels;
}
if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
if (!(is_evpn_tunnel_type_vxlan(afi, safi,
attr->encap_tunneltype)))
bgp_set_valid_label(&extra->label[0]);
}

Expand Down Expand Up @@ -10908,7 +10917,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,

/* Filter prefix using route-map */
ret = bgp_input_modifier(peer, &rn->p, &attr,
afi, safi, rmap_name);
afi, safi, rmap_name, NULL, 0);

if (type == bgp_show_adj_route_filtered &&
!route_filtered && ret != RMAP_DENY) {
Expand Down
35 changes: 30 additions & 5 deletions bgpd/bgp_routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,25 +803,50 @@ struct route_map_rule_cmd route_match_mac_address_cmd = {
route_match_mac_address_free};

/* `match vni' */

/* Match function should return 1 if match is success else return
zero. */
/*
* Match function returns:
* ...RMAP_MATCH if match is found.
* ...RMAP_NOMATCH if match is not found.
* ...RMAP_OKAY to bypass this check..
*/
static route_map_result_t route_match_vni(void *rule,
const struct prefix *prefix,
route_map_object_t type, void *object)
{
vni_t vni = 0;
unsigned int label_cnt = 0;
struct bgp_path_info *path = NULL;
struct prefix_evpn *evp = (struct prefix_evpn*)prefix;

if (type == RMAP_BGP) {
vni = *((vni_t *)rule);
path = (struct bgp_path_info *)object;

/*
* This rmap filter is valid for vxlan tunnel type only.
* For any other tunnel type, return RMAP_OKAY, so, we don't
* RMAP_DENY this, which can happen by returning
* RMAP_MATCH or RMAP_NOMATCH.
*/
if (path->attr && path->attr->encap_tunneltype !=
BGP_ENCAP_TYPE_VXLAN)
return RMAP_OKAY;

/*
We do not want to filter type 3 routes because
they do not have vni associated with them.
*/
if (evp && evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)
return RMAP_OKAY;

if (path->extra == NULL)
return RMAP_NOMATCH;

if (vni == label2vni(&path->extra->label[0]))
return RMAP_MATCH;
for ( ; label_cnt < BGP_MAX_LABELS &&
label_cnt < path->extra->num_labels; label_cnt++) {
if (vni == label2vni(&path->extra->label[label_cnt]))
return RMAP_MATCH;
}
}

return RMAP_NOMATCH;
Expand Down

0 comments on commit b513aaa

Please sign in to comment.