diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f197ad16a3..3f3acbe0e2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2701,8 +2701,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id, struct attr *attr) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, + struct attr *attr) { if (safi == SAFI_MPLS_VPN) { if (addpath_encode) @@ -2714,8 +2715,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, stream_put(s, &p->u.prefix, PSIZE(p->prefixlen)); } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) { /* EVPN prefix - contents depend on type */ - bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode, - addpath_tx_id); + bgp_evpn_encode_prefix(s, p, prd, label, num_labels, + attr, addpath_encode, addpath_tx_id); } else if (safi == SAFI_LABELED_UNICAST) { /* Prefix write with label. */ stream_put_labeled_prefix(s, p, label); @@ -2843,8 +2844,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id) { size_t cp; size_t aspath_sizep; @@ -2866,7 +2867,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, + label, num_labels, addpath_encode, addpath_tx_id, attr); bgp_packet_mpattr_end(s, mpattrlen_pos); } @@ -3298,15 +3300,19 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id, struct attr *attr) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, + struct attr *attr) { u_char wlabel[3] = {0x80, 0x00, 0x00}; - if (safi == SAFI_LABELED_UNICAST) + if (safi == SAFI_LABELED_UNICAST) { label = (mpls_label_t *)wlabel; + num_labels = 1; + } - return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, + label, num_labels, addpath_encode, addpath_tx_id, attr); } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index ebe14a7ceb..1b1471a198 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -260,7 +260,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct bpacket_attr_vec_arr *vecarr, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, - mpls_label_t *, int, u_int32_t); + mpls_label_t *, u_int32_t, + int, u_int32_t); extern void bgp_dump_routes_attr(struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp(const void *, const void *); @@ -308,7 +309,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, struct attr *attr); extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p); @@ -318,7 +320,8 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi, safi_t safi, - struct prefix_rd *prd, mpls_label_t *, + struct prefix_rd *prd, + mpls_label_t *, u_int32_t, int, u_int32_t, struct attr *); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 45ac8e6859..b08522b68b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2017,8 +2017,9 @@ int bgp_debug_zebra(struct prefix *p) const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, struct prefix_rd *prd, union prefixconstptr pu, - mpls_label_t *label, int addpath_valid, - u_int32_t addpath_id, char *str, int size) + mpls_label_t *label, u_int32_t num_labels, + int addpath_valid, u_int32_t addpath_id, + char *str, int size) { char rd_buf[RD_ADDRSTRLEN]; char pfx_buf[PREFIX_STRLEN]; @@ -2041,11 +2042,19 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, addpath_id); tag_buf[0] = '\0'; - if (bgp_labeled_safi(safi) && label) { - u_int32_t label_value; + if (bgp_labeled_safi(safi) && num_labels) { - label_value = decode_label(label); - sprintf(tag_buf, " label %u", label_value); + if (safi == SAFI_EVPN) { + char tag_buf2[20]; + + bgp_evpn_label2str(label, num_labels, tag_buf2, 20); + sprintf(tag_buf, " label %s", tag_buf2); + } else { + u_int32_t label_value; + + label_value = decode_label(label); + sprintf(tag_buf, " label %u", label_value); + } } if (prd) diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 5fe19b162b..7c773cfafb 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -153,7 +153,8 @@ extern int bgp_debug_zebra(struct prefix *p); extern int bgp_debug_count(void); extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *, - union prefixconstptr, mpls_label_t *, + union prefixconstptr, + mpls_label_t *, u_int32_t, int, u_int32_t, char *, int); const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data, size_t datalen); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 46a983a880..b20076d471 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1034,10 +1034,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); @@ -1127,11 +1128,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 @@ -1196,9 +1201,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; - memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); + l3vni = bgpevpn_get_l3vni(vpn); + if (l3vni) { + vni2label(l3vni, &label[1]); + num_labels++; + } + } + + 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; @@ -1814,9 +1830,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) @@ -1880,9 +1898,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) @@ -2772,7 +2792,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 @@ -2840,19 +2861,28 @@ 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 += 3; + psize -= (33 + ipaddr_len); + /* Do we have a second VNI? */ + if (psize) { + num_labels++; + memcpy(&label[1], pfx, BGP_LABEL_BYTES); + pfx += 3; + } /* 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; } @@ -2908,11 +2938,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; } @@ -2928,7 +2958,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: @@ -2994,23 +3024,27 @@ 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); + pfx += 3; /* 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; @@ -3055,7 +3089,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); @@ -3447,14 +3481,20 @@ 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; } @@ -3577,12 +3617,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); @@ -3596,18 +3637,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: @@ -3621,7 +3668,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: diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 9400916845..b3b61db141 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -34,6 +34,27 @@ static inline int is_evpn_enabled(void) return bgp ? bgp->advertise_all_vni : 0; } +static inline void vni2label(vni_t vni, mpls_label_t *label) +{ + u_char *tag = (u_char *)label; + + tag[0] = (vni >> 16) & 0xFF; + tag[1] = (vni >> 8) & 0xFF; + tag[2] = vni & 0xFF; +} + +static inline vni_t label2vni(mpls_label_t *label) +{ + u_char *tag = (u_char *)label; + vni_t vni; + + vni = ((u_int32_t)*tag++ << 16); + vni |= (u_int32_t)*tag++ << 8; + vni |= (u_int32_t)(*tag & 0xFF); + + return vni; +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn, afi_t afi, safi_t safi); @@ -46,11 +67,13 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); -extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len); +extern char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels, + char *buf, int len); extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len); extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json); extern 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); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f5a0998f62..6003e03f35 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -228,26 +228,6 @@ static inline int is_vni_param_configured(struct bgpevpn *vpn) || is_export_rt_configured(vpn)); } -static inline void vni2label(vni_t vni, mpls_label_t *label) -{ - u_char *tag = (u_char *)label; - tag[0] = (vni >> 16) & 0xFF; - tag[1] = (vni >> 8) & 0xFF; - tag[2] = vni & 0xFF; -} - -static inline vni_t label2vni(mpls_label_t *label) -{ - u_char *tag = (u_char *)label; - vni_t vni; - - vni = ((u_int32_t)*tag++ << 16); - vni |= (u_int32_t)*tag++ << 8; - vni |= (u_int32_t)(*tag & 0xFF); - - return vni; -} - static inline void encode_rmac_extcomm(struct ecommunity_val *eval, struct ethaddr *rmac) { diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 60250513b6..38b39075be 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -103,7 +103,7 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri, if (!rn || !ri || !to) return MPLS_INVALID_LABEL; - remote_label = ri->extra ? ri->extra->label : MPLS_INVALID_LABEL; + remote_label = ri->extra ? ri->extra->label[0] : MPLS_INVALID_LABEL; from = ri->peer; reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); @@ -325,11 +325,11 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, if (attr) { bgp_update(peer, &p, addpath_id, attr, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, 0, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1, 0, NULL); } else { bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1, NULL); } } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 472b9d200a..0e2594ba8a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -214,11 +214,11 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, if (attr) { bgp_update(peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, 0, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL); } else { bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); } } /* Packet length consistency check. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fdc7f22ae8..234bde418b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -147,7 +147,8 @@ static struct bgp_info_extra *bgp_info_extra_new(void) { struct bgp_info_extra *new; new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_info_extra)); - new->label = MPLS_INVALID_LABEL; + new->label[0] = MPLS_INVALID_LABEL; + new->num_labels = 0; return new; } @@ -770,9 +771,9 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new, /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - if ((new->extra &&bgp_is_valid_label(&new->extra->label)) + if ((new->extra && bgp_is_valid_label(&new->extra->label[0])) != (exist->extra - && bgp_is_valid_label(&exist->extra->label))) { + && bgp_is_valid_label(&exist->extra->label[0]))) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", @@ -2670,7 +2671,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, - int sub_type, struct prefix_rd *prd, mpls_label_t *label, + int sub_type, struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn) { int ret; @@ -2681,9 +2683,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; + struct bgp_info_extra *extra; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; - char label_buf[20]; int connected = 0; int do_loop_check = 1; int has_valid_label = 0; @@ -2698,10 +2700,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, bgp = peer->bgp; rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); - has_valid_label = bgp_is_valid_label(label); - - if (has_valid_label) - sprintf(label_buf, "label %u", label_pton(label)); + /* 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; + else + has_valid_label = bgp_is_valid_label(label); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -2821,7 +2824,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, && attrhash_cmp(ri->attr, attr_new) && (!has_valid_label || memcmp(&(bgp_info_extra_get(ri))->label, label, - BGP_LABEL_BYTES) + num_labels * sizeof(mpls_label_t)) == 0) && (overlay_index_equal( afi, ri, evpn == NULL ? NULL : &evpn->eth_s_id, @@ -2832,7 +2835,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, @@ -2857,7 +2861,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, } bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -2883,7 +2888,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -2896,7 +2902,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, pfx_buf); @@ -2987,9 +2994,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { - memcpy(&(bgp_info_extra_get(ri))->label, label, - BGP_LABEL_BYTES); - bgp_set_valid_label(&(bgp_info_extra_get(ri))->label); + extra = bgp_info_extra_get(ri); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) + bgp_set_valid_label(&extra->label[0]); } #if ENABLE_BGP_VNC @@ -3126,7 +3136,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, pfx_buf); @@ -3137,9 +3148,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { - memcpy(&(bgp_info_extra_get(new))->label, label, - BGP_LABEL_BYTES); - bgp_set_valid_label(&(bgp_info_extra_get(new))->label); + extra = bgp_info_extra_get(new); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) + bgp_set_valid_label(&extra->label[0]); } /* Update Overlay Index */ @@ -3241,7 +3255,8 @@ filtered: peer->rcvd_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s", @@ -3276,7 +3291,8 @@ filtered: int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, - int sub_type, struct prefix_rd *prd, mpls_label_t *label, + int sub_type, struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct bgp_route_evpn *evpn) { struct bgp *bgp; @@ -3312,7 +3328,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (!bgp_adj_in_unset(rn, peer, addpath_id)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -3332,7 +3349,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host, @@ -3343,7 +3361,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw(rn, ri, peer, afi, safi, prd); else if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s Can't find the route %s", peer->host, pfx_buf); @@ -3469,14 +3488,18 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, continue; struct bgp_info *ri = rn->info; - mpls_label_t label = (ri && ri->extra) - ? ri->extra->label - : MPLS_INVALID_LABEL; + u_int32_t num_labels = 0; + mpls_label_t *label_pnt = NULL; + + if (ri && ri->extra) + num_labels = ri->extra->num_labels; + if (num_labels) + label_pnt = &ri->extra->label[0]; ret = bgp_update(peer, &rn->p, ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, prd, &label, 1, - NULL); + BGP_ROUTE_NORMAL, prd, + label_pnt, num_labels, 1, NULL); if (ret < 0) { bgp_unlock_node(rn); @@ -4029,11 +4052,12 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, if (attr) ret = bgp_update(peer, &p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - NULL, NULL, 0, NULL); + NULL, NULL, 0, 0, NULL); else ret = bgp_withdraw(peer, &p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, NULL, NULL); + BGP_ROUTE_NORMAL, NULL, + NULL, 0, NULL); /* Address family configuration mismatch or maximum-prefix count overflow. */ @@ -4345,10 +4369,13 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, #if ENABLE_BGP_VNC mpls_label_t label = 0; #endif + u_int32_t num_labels = 0; union gw_addr add; assert(bgp_static); + if (bgp_static->label != MPLS_INVALID_LABEL) + num_labels = 1; rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, &bgp_static->prd); @@ -4466,7 +4493,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, attr_new, rn); SET_FLAG(new->flags, BGP_INFO_VALID); new->extra = bgp_info_extra_new(); - new->extra->label = bgp_static->label; + if (num_labels) { + new->extra->label[0] = bgp_static->label; + new->extra->num_labels = num_labels; + } #if ENABLE_BGP_VNC label = decode_label(&bgp_static->label); #endif @@ -6713,7 +6743,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, } } - label = decode_label(&binfo->extra->label); + label = decode_label(&binfo->extra->label[0]); if (bgp_is_valid_label(&label)) { if (json) { @@ -7051,14 +7081,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, #if defined(HAVE_CUMULUS) if (!json_paths && safi == SAFI_EVPN) { - char tag_buf[20]; + char tag_buf[30]; bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2)); vty_out(vty, " Route %s", buf2); tag_buf[0] = '\0'; - if (binfo->extra) { - bgp_evpn_label2str(&binfo->extra->label, tag_buf, - sizeof(tag_buf)); + if (binfo->extra && binfo->extra->num_labels) { + bgp_evpn_label2str(binfo->extra->label, + binfo->extra->num_labels, + tag_buf, sizeof(tag_buf)); vty_out(vty, " VNI %s", tag_buf); } vty_out(vty, "\n"); @@ -7692,13 +7723,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, /* Remote Label */ #if defined(HAVE_CUMULUS) - if (binfo->extra && bgp_is_valid_label(&binfo->extra->label) + if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]) && safi != SAFI_EVPN) #else - if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)) + if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])) #endif { - mpls_label_t label = label_pton(&binfo->extra->label); + mpls_label_t label = label_pton( + &binfo->extra->label[0]); if (json_paths) json_object_int_add(json_path, "remoteLabel", label); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index ae4759aad0..cd4d027c6e 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -59,6 +59,11 @@ enum bgp_show_type { #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n" #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" +/* Maximum number of labels we can process or send with a prefix. We + * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. + */ +#define BGP_MAX_LABELS 2 + /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. @@ -73,11 +78,9 @@ struct bgp_info_extra { /* Nexthop reachability check. */ u_int32_t igpmetric; - /* MPLS label - L2VNI */ - mpls_label_t label; - - /* MPLS label - L3-VNI */ - mpls_label_t label2; + /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ + mpls_label_t label[BGP_MAX_LABELS]; + u_int32_t num_labels; #if ENABLE_BGP_VNC union { @@ -360,10 +363,10 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *, /* this is primarily for MPLS-VPN */ extern int bgp_update(struct peer *, struct prefix *, u_int32_t, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, - mpls_label_t *, int, struct bgp_route_evpn *); + mpls_label_t *, u_int32_t, int, struct bgp_route_evpn *); extern int bgp_withdraw(struct peer *, struct prefix *, u_int32_t, struct attr *, afi_t, safi_t, int, int, - struct prefix_rd *, mpls_label_t *, + struct prefix_rd *, mpls_label_t *, u_int32_t, struct bgp_route_evpn *); /* for bgp_nexthop and bgp_damp */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8c9f9f65ca..de2410e009 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -659,7 +659,7 @@ static route_map_result_t route_match_vni(void *rule, struct prefix *prefix, vni = *((vni_t *)rule); bgp_info = (struct bgp_info *)object; - if (vni == label2vni(&bgp_info->extra->label)) + if (vni == label2vni(&bgp_info->extra->label[0])) return RMAP_MATCH; } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index b63dfbed0a..9fa733a720 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -701,7 +701,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) int addpath_overhead = 0; u_int32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; - mpls_label_t label = MPLS_INVALID_LABEL; + mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL; + u_int32_t num_labels = 0; if (!subgrp) return NULL; @@ -772,7 +773,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) * attr. */ total_attr_len = bgp_packet_attribute( NULL, peer, s, adv->baa->attr, &vecarr, NULL, - afi, safi, from, NULL, NULL, 0, 0); + afi, safi, from, NULL, NULL, 0, 0, 0); space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) @@ -815,11 +816,15 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) if (rn->prn) prd = (struct prefix_rd *)&rn->prn->p; - if (safi == SAFI_LABELED_UNICAST) + if (safi == SAFI_LABELED_UNICAST) { label = bgp_adv_label(rn, binfo, peer, afi, safi); - else if (binfo && binfo->extra) - label = binfo->extra->label; + label_pnt = &label; + num_labels = 1; + } else if (binfo && binfo->extra) { + label_pnt = &binfo->extra->label[0]; + num_labels = binfo->extra->num_labels; + } if (stream_empty(snlri)) mpattrlen_pos = bgp_packet_mpattr_start( @@ -827,8 +832,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) adv->baa->attr); bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, - &label, addpath_encode, - addpath_tx_id, adv->baa->attr); + label_pnt, num_labels, + addpath_encode, addpath_tx_id, + adv->baa->attr); } num_pfx++; @@ -857,7 +863,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) send_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, &label, + bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, + label_pnt, num_labels, addpath_encode, addpath_tx_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", @@ -1009,7 +1016,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) } bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, - NULL, addpath_encode, + NULL, 0, addpath_encode, addpath_tx_id, NULL); } @@ -1018,7 +1025,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { char pfx_buf[BGP_PRD_PATH_STRLEN]; - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, + bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0, addpath_encode, addpath_tx_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 @@ -1132,7 +1139,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, stream_putw(s, 0); total_attr_len = bgp_packet_attribute( NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL, - addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); + 0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); /* Set Total Path Attribute Length. */ stream_putw_at(s, pos, total_attr_len); @@ -1227,7 +1234,7 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp) mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); bgp_packet_mpunreach_prefix( - s, &p, afi, safi, NULL, NULL, addpath_encode, + s, &p, afi, safi, NULL, NULL, 0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL); /* Set the mp_unreach attr's length */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index de170fdd01..2a35645ee8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1142,10 +1142,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; } - if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label) + if (mpinfo->extra && + bgp_is_valid_label(&mpinfo->extra->label[0]) && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { has_valid_label = 1; - label = label_pton(&mpinfo->extra->label); + label = label_pton(&mpinfo->extra->label[0]); api_nh->label_num = 1; api_nh->labels[0] = label; diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index d4921ce40a..a37e705612 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -317,7 +317,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn, iattr, /* bgp_update copies this attr */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, /* tag not used for unicast */ + NULL, 0, /* tag not used for unicast */ 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); }