diff options
Diffstat (limited to 'bgpd/bgp_evpn.c')
| -rw-r--r-- | bgpd/bgp_evpn.c | 327 |
1 files changed, 246 insertions, 81 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 824b72b240..c7d5f8d111 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -484,7 +484,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn) static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, struct prefix_evpn *p, struct in_addr remote_vtep_ip, int add, - u_char sticky) + u_char flags) { struct stream *s; int ipa_len; @@ -519,18 +519,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, } stream_put_in_addr(s, &remote_vtep_ip); - /* TX MAC sticky status */ + /* TX flags - MAC sticky status and/or gateway mac */ if (add) - stream_putc(s, sticky); + stream_putc(s, flags); stream_putw_at(s, 0, stream_get_endp(s)); if (bgp_debug_zebra(NULL)) - zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s", + zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s", add ? "ADD" : "DEL", vpn->vni, - sticky ? "sticky " : "", prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)), ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)), + flags, inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); @@ -640,9 +640,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, { struct ecommunity ecom_encap; struct ecommunity ecom_sticky; + struct ecommunity ecom_default_gw; struct ecommunity ecom_rmac; struct ecommunity_val eval; struct ecommunity_val eval_sticky; + struct ecommunity_val eval_default_gw; struct ecommunity_val eval_rmac; bgp_encap_types tnl_type; struct listnode *node, *nnode; @@ -697,6 +699,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, &ecom_rmac); } + if (attr->default_gw) { + memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + encode_default_gw_extcomm(&eval_default_gw); + ecom_default_gw.size = 1; + ecom_default_gw.val = (uint8_t *)eval_default_gw.val; + attr->ecommunity = ecommunity_merge(attr->ecommunity, + &ecom_default_gw); + } + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -754,13 +765,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) /* Install EVPN route into zebra. */ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, struct prefix_evpn *p, - struct in_addr remote_vtep_ip, u_char sticky) + struct in_addr remote_vtep_ip, u_char flags) { int ret; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, - 1, sticky); + 1, flags); else ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1); @@ -831,6 +842,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; + u_char flags = 0; /* Compute the best path. */ bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new, @@ -848,11 +860,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && !bgp->addpath_tx_used[afi][safi]) { - if (bgp_zebra_has_route_changed(rn, old_select)) + if (bgp_zebra_has_route_changed(rn, old_select)) { + if (old_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (old_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, old_select->attr->nexthop, - old_select->attr->sticky); + flags); + } UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(rn); return ret; @@ -877,9 +894,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_NORMAL) { + flags = 0; + if (new_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (new_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, new_select->attr->nexthop, - new_select->attr->sticky); + flags); /* If an old best existed and it was a "local" route, the only * reason * it would be supplanted is due to MAC mobility procedures. So, @@ -909,6 +931,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, return ret; } +/* + * Return true if the local ri for this rn is of type gateway mac + */ +static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn) +{ + struct bgp_info *tmp_ri = NULL; + struct bgp_info *local_ri = NULL; + + local_ri = NULL; + for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) { + if (tmp_ri->peer == bgp->peer_self + && tmp_ri->type == ZEBRA_ROUTE_BGP + && tmp_ri->sub_type == BGP_ROUTE_STATIC) + local_ri = tmp_ri; + } + + if (!local_ri) + return 0; + + return local_ri->attr->default_gw; +} + /* * Return true if the local ri for this rn has sticky set @@ -968,10 +1012,11 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def, bgp_def->peer_self, attr_new, rn); SET_FLAG(ri->flags, BGP_INFO_VALID); - /* L3-VNI goes in the label2 field */ + /* Type-5 routes advertise the L3-VNI */ bgp_info_extra_get(ri); vni2label(bgp_vrf->l3vni, &label); - memcpy(&ri->extra->label2, &label, BGP_LABEL_BYTES); + memcpy(&ri->extra->label, &label, sizeof(label)); + ri->extra->num_labels = 1; /* add the route entry to route node*/ bgp_info_add(rn, ri); @@ -1003,7 +1048,8 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def, /* update evpn type-5 route entry */ static int update_evpn_type5_route(struct bgp *bgp_vrf, - struct prefix_evpn *evp) + struct prefix_evpn *evp, + struct attr* src_attr) { afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; @@ -1014,11 +1060,18 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, bgp_def = bgp_get_default(); if (!bgp_def) - return -1; + return 0; - /* build path attribute for this route */ - memset(&attr, 0, sizeof(struct attr)); - bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); + /* Build path attribute for this route - use the source attr, if + * present, else treat as locally originated. + */ + if (src_attr) + bgp_attr_dup(&attr, src_attr); + else { + memset(&attr, 0, sizeof(struct attr)); + bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); + } + /* Set nexthop to ourselves and fill in the Router MAC. */ attr.nexthop = bgp_vrf->originator_ip; attr.mp_nexthop_global_in = bgp_vrf->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; @@ -1045,7 +1098,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, } /* uninten temporary */ - aspath_unintern(&attr.aspath); + if (!src_attr) + aspath_unintern(&attr.aspath); return 0; } @@ -1061,11 +1115,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_info *tmp_ri; struct bgp_info *local_ri, *remote_ri; struct attr *attr_new; - mpls_label_t label = MPLS_INVALID_LABEL; + mpls_label_t label[BGP_MAX_LABELS]; + u_int32_t num_labels = 1; int route_change = 1; u_char sticky = 0; + struct prefix_evpn *evp; *ri = NULL; + evp = (struct prefix_evpn *)&rn->p; + memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. Also, * identify if already known from remote, and if so, the one with the @@ -1107,7 +1165,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * SVI) advertised in EVPN. * This will ensure that local routes are preferred for g/w macs */ - if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) { + if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { u_int32_t cur_seqnum; /* Add MM extended community to route. */ @@ -1130,9 +1188,20 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bgp_info_extra_get(tmp_ri); /* The VNI goes into the 'label' field of the route */ - vni2label(vpn->vni, &label); + vni2label(vpn->vni, &label[0]); + /* Type-2 routes may carry a second VNI - the L3-VNI */ + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + vni_t l3vni; + + l3vni = bgpevpn_get_l3vni(vpn); + if (l3vni) { + vni2label(l3vni, &label[1]); + num_labels++; + } + } - memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); + memcpy(&tmp_ri->extra->label, label, sizeof(label)); + tmp_ri->extra->num_labels = num_labels; bgp_info_add(rn, tmp_ri); } else { tmp_ri = local_ri; @@ -1183,8 +1252,9 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; + attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); bgpevpn_get_rmac(vpn, &attr.rmac); vni2label(vpn->vni, &(attr.label)); @@ -1270,7 +1340,7 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, bgp_def = bgp_get_default(); if (!bgp_def) - return -1; + return 0; /* locate the global route entry for this type-5 prefix */ rn = bgp_afi_node_lookup(bgp_def->rib[afi][safi], afi, safi, @@ -1372,22 +1442,27 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) struct bgp_info *ri; struct attr attr; struct attr attr_sticky; + struct attr attr_def_gw; struct attr attr_ip6; struct attr attr_sticky_ip6; + struct attr attr_def_gw_ip6; struct attr *attr_new; afi = AFI_L2VPN; safi = SAFI_EVPN; memset(&attr, 0, sizeof(struct attr)); memset(&attr_sticky, 0, sizeof(struct attr)); + memset(&attr_def_gw, 0, sizeof(struct attr)); memset(&attr_ip6, 0, sizeof(struct attr)); memset(&attr_sticky_ip6, 0, sizeof(struct attr)); + memset(&attr_def_gw_ip6, 0, sizeof(struct attr)); /* Build path-attribute - all type-2 routes for this VNI will share the * same path attribute. */ bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP); + bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP); attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; @@ -1397,8 +1472,14 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_sticky.sticky = 1; bgpevpn_get_rmac(vpn, &attr_sticky.rmac); + attr_def_gw.nexthop = vpn->originator_ip; + attr_def_gw.mp_nexthop_global_in = vpn->originator_ip; + attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_def_gw.default_gw = 1; + bgpevpn_get_rmac(vpn, &attr_def_gw.rmac); bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP); bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP); + bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP); attr_ip6.nexthop = vpn->originator_ip; attr_ip6.mp_nexthop_global_in = vpn->originator_ip; attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; @@ -1408,12 +1489,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr_sticky_ip6.sticky = 1; bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac); + attr_def_gw_ip6.nexthop = vpn->originator_ip; + attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip; + attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; + attr_def_gw_ip6.default_gw = 1; + bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac); /* Set up RT, ENCAP and sticky MAC extended community. */ build_evpn_route_extcomm(vpn, &attr, AFI_IP); build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP); + build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP); build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6); build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6); + build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP); /* Walk this VNI's route table and update local type-2 routes. For any * routes updated, update corresponding entry in the global table too. @@ -1432,6 +1520,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri, 0); + else if (evpn_route_is_def_gw(bgp, rn)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_def_gw, 0, 1, + &ri, 0); else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri, 0); @@ -1440,6 +1532,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky_ip6, 0, 1, &ri, 0); + else if (evpn_route_is_def_gw(bgp, rn)) + update_evpn_route_entry(bgp, vpn, afi, safi, rn, + &attr_def_gw_ip6, 0, 1, + &ri, 0); else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_ip6, 0, 1, @@ -1474,7 +1570,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Unintern temporary. */ aspath_unintern(&attr.aspath); + aspath_unintern(&attr_ip6.aspath); aspath_unintern(&attr_sticky.aspath); + aspath_unintern(&attr_sticky_ip6.aspath); + aspath_unintern(&attr_def_gw.aspath); + aspath_unintern(&attr_def_gw_ip6.aspath); return 0; } @@ -1717,9 +1817,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, SET_FLAG(ri->flags, BGP_INFO_VALID); bgp_info_extra_get(ri); ri->extra->parent = parent_ri; - if (parent_ri->extra) + if (parent_ri->extra) { memcpy(&ri->extra->label, &parent_ri->extra->label, - BGP_LABEL_BYTES); + sizeof(ri->extra->label)); + ri->extra->num_labels = parent_ri->extra->num_labels; + } bgp_info_add(rn, ri); } else { if (attrhash_cmp(ri->attr, parent_ri->attr) @@ -1783,9 +1885,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(ri->flags, BGP_INFO_VALID); bgp_info_extra_get(ri); ri->extra->parent = parent_ri; - if (parent_ri->extra) + if (parent_ri->extra) { memcpy(&ri->extra->label, &parent_ri->extra->label, - BGP_LABEL_BYTES); + sizeof(ri->extra->label)); + ri->extra->num_labels = parent_ri->extra->num_labels; + } bgp_info_add(rn, ri); } else { if (attrhash_cmp(ri->attr, parent_ri->attr) @@ -2675,7 +2779,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, struct prefix_evpn p; u_char ipaddr_len; u_char macaddr_len; - mpls_label_t *label_pnt; + mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */ + u_int32_t num_labels = 0; int ret; /* Type-2 route should be either 33, 37 or 49 bytes or an @@ -2743,19 +2848,31 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, } pfx += ipaddr_len; - /* Get the VNI (in MPLS label field). */ - /* Note: We ignore the second VNI, if any. */ - label_pnt = (mpls_label_t *)pfx; + /* Get the VNI(s). Stored as bytes here. */ + num_labels++; + memset(label, 0, sizeof(label)); + memcpy(&label[0], pfx, BGP_LABEL_BYTES); + pfx += BGP_LABEL_BYTES; + psize -= (33 + ipaddr_len); + /* Do we have a second VNI? */ + if (psize) { + num_labels++; + memcpy(&label[1], pfx, BGP_LABEL_BYTES); + /* + * If in future, we are required to access additional fields, + * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field + */ + } /* Process the route. */ if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, 0, NULL); + &prd, &label[0], num_labels, 0, NULL); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, NULL); + &prd, &label[0], num_labels, NULL); return ret; } @@ -2811,11 +2928,11 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, NULL, 0, NULL); + &prd, NULL, 0, 0, NULL); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, NULL, NULL); + &prd, NULL, 0, NULL); return ret; } @@ -2831,7 +2948,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, struct bgp_route_evpn evpn; u_char ippfx_len; u_int32_t eth_tag; - mpls_label_t *label_pnt; + mpls_label_t label; /* holds the VNI as in the packet */ int ret; /* Type-5 route should be 34 or 58 bytes: @@ -2897,23 +3014,31 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, pfx += 16; } - label_pnt = (mpls_label_t *)pfx; + /* Get the VNI (in MPLS label field). Stored as bytes here. */ + memset(&label, 0, sizeof(label)); + memcpy(&label, pfx, BGP_LABEL_BYTES); + + /* + * If in future, we are required to access additional fields, + * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field + */ /* Process the route. */ if (!withdraw) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, 0, &evpn); + &prd, &label, 1, 0, &evpn); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, &evpn); + &prd, &label, 1, &evpn); return ret; } static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, + struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct attr *attr) { int len; @@ -2958,7 +3083,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, stream_put(s, &temp, 16); } - if (label) + if (num_labels) stream_put(s, label, 3); else stream_put3(s, 0); @@ -3057,20 +3182,24 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf) */ /* withdraw type-5 route corresponding to ip prefix */ -void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn, +void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p, afi_t afi, safi_t safi) { int ret = 0; struct prefix_evpn evp; char buf[PREFIX_STRLEN]; - build_type5_prefix_from_ip_prefix(&evp, &rn->p); + /* NOTE: Check needed as this is called per-route also. */ + if (!advertise_type5_routes(bgp_vrf, afi)) + return; + + build_type5_prefix_from_ip_prefix(&evp, p); ret = delete_evpn_type5_route(bgp_vrf, &evp); if (ret) { zlog_err( "%u failed to delete type-5 route for prefix %s in vrf %s", bgp_vrf->vrf_id, - prefix2str(&rn->p, buf, sizeof(buf)), + prefix2str(p, buf, sizeof(buf)), vrf_id_to_name(bgp_vrf->vrf_id)); } } @@ -3082,54 +3211,77 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, struct bgp_table *table = NULL; struct bgp_node *rn = NULL; + /* Bail out early if we don't have to advertise type-5 routes. */ if (!advertise_type5_routes(bgp_vrf, afi)) return; table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) - bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi); + bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi); } -/* advertise ip prefix as type-5 route*/ -void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn, +/* + * Advertise IP prefix as type-5 route. The afi/safi and src_attr passed + * to this function correspond to those of the source IP prefix (best + * path in the case of the attr. In the case of a local prefix (when we + * are advertising local subnets), the src_attr will be NULL. + */ +void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, + struct attr *src_attr, afi_t afi, safi_t safi) { int ret = 0; struct prefix_evpn evp; char buf[PREFIX_STRLEN]; + /* NOTE: Check needed as this is called per-route also. */ if (!advertise_type5_routes(bgp_vrf, afi)) return; - if (!rn->info) - return; - /* only advertise subnet routes as type-5 */ - if (is_host_route(&rn->p)) + if (is_host_route(p)) return; - build_type5_prefix_from_ip_prefix(&evp, &rn->p); - ret = update_evpn_type5_route(bgp_vrf, &evp); - if (ret) { + build_type5_prefix_from_ip_prefix(&evp, p); + ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr); + if (ret) zlog_err( - "%u failed to create type-5 route for prefix %s in vrf %s", + "%u: Failed to create type-5 route for prefix %s", bgp_vrf->vrf_id, - prefix2str(&rn->p, buf, sizeof(buf)), - vrf_id_to_name(bgp_vrf->vrf_id)); - } + prefix2str(p, buf, sizeof(buf))); } -/* advertise all type-5 routes for an address family */ +/* Inject all prefixes of a particular address-family (currently, IPv4 or + * IPv6 unicast) into EVPN as type-5 routes. This is invoked when the + * advertisement is enabled. + */ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi) { struct bgp_table *table = NULL; struct bgp_node *rn = NULL; + struct bgp_info *ri; + + /* Bail out early if we don't have to advertise type-5 routes. */ + if (!advertise_type5_routes(bgp_vrf, afi)) + return; table = bgp_vrf->rib[afi][safi]; - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) - bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi); + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + /* Need to identify the "selected" route entry to use its + * attribute. + * TODO: Support for AddPath for EVPN. + */ + for (ri = rn->info; ri; ri = ri->next) { + if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) { + bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, + ri->attr, + afi, safi); + break; + } + } + } } void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, @@ -3350,14 +3502,19 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) } /* - * Function to display "tag" in route as a VNI. + * TODO: Hardcoded for a maximum of 2 VNIs right now */ -char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) +char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels, + char *buf, int len) { - vni_t vni; + vni_t vni1, vni2; - vni = label2vni(label); - snprintf(buf, len, "%u", vni); + vni1 = label2vni(label); + if (num_labels == 2) { + vni2 = label2vni(label+1); + snprintf(buf, len, "%u/%u", vni1, vni2); + } else + snprintf(buf, len, "%u", vni1); return buf; } @@ -3461,7 +3618,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) PREFIX2STR_BUFFER)); } } else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { - snprintf(buf, len, "[%d]:[0]:[%d]:[%s]", + snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]", p->prefix.route_type, p->prefix.ip_prefix_length, IS_EVPN_PREFIX_IPADDR_V4(p) ? @@ -3480,12 +3637,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) * Encode EVPN prefix in Update (MP_REACH) */ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, + struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct attr *attr, int addpath_encode, u_int32_t addpath_tx_id) { struct prefix_evpn *evp = (struct prefix_evpn *)p; - int ipa_len = 0; + int len, ipa_len = 0; if (addpath_encode) stream_putl(s, addpath_tx_id); @@ -3499,18 +3657,24 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, ipa_len = IPV4_MAX_BYTELEN; else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) ipa_len = IPV6_MAX_BYTELEN; - stream_putc(s, 33 + ipa_len); // 1 VNI + /* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */ + len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3; + if (ipa_len && num_labels > 1) /* There are 2 VNIs */ + len += 3; + stream_putc(s, len); stream_put(s, prd->val, 8); /* RD */ stream_put(s, 0, 10); /* ESI */ stream_putl(s, 0); /* Ethernet Tag ID */ stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */ stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */ stream_putc(s, 8 * ipa_len); /* IP address Length */ - if (ipa_len) - stream_put(s, &evp->prefix.ip.ip.addr, - ipa_len); /* IP */ - stream_put(s, label, - BGP_LABEL_BYTES); /* VNI is contained in 'tag' */ + if (ipa_len) /* IP */ + stream_put(s, &evp->prefix.ip.ip.addr, ipa_len); + /* 1st label is the L2 VNI */ + stream_put(s, label, BGP_LABEL_BYTES); + /* Include 2nd label (L3 VNI) if advertising MAC+IP */ + if (ipa_len && num_labels > 1) + stream_put(s, label+1, BGP_LABEL_BYTES); break; case BGP_EVPN_IMET_ROUTE: @@ -3524,7 +3688,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, case BGP_EVPN_IP_PREFIX_ROUTE: /* TODO: AddPath support. */ - evpn_mpattr_encode_type5(s, p, prd, label, attr); + evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr); break; default: @@ -4020,12 +4184,13 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, char buf2[INET6_ADDRSTRLEN]; zlog_err( - "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s", + "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)", bgp->vrf_id, vpn->vni, - CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway" + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "sticky gateway" : "", prefix_mac2str(mac, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2))); + ipaddr2str(ip, buf2, sizeof(buf2)), + flags); return -1; } |
