diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 206d91bfe9..3f3acbe0e2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1876,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); attr->sticky = sticky; + /* Check if this is a Gateway MAC-IP advertisement */ + attr->default_gw = bgp_attr_default_gw(attr); + /* Extract the Rmac, if any */ bgp_attr_rmac(attr, &attr->rmac); @@ -2698,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) @@ -2711,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); @@ -2840,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; @@ -2863,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); } @@ -3295,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 1de1bee0f9..1b1471a198 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -162,6 +162,9 @@ struct attr { /* Static MAC for EVPN */ u_char sticky; + /* Flag for default gateway extended community in EVPN */ + u_char default_gw; + /* route tag */ route_tag_t tag; @@ -257,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 *); @@ -305,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); @@ -315,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_attr_evpn.c b/bgpd/bgp_attr_evpn.c index eaa4e329d4..e74fa5a2be 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -134,6 +134,36 @@ void bgp_attr_rmac(struct attr *attr, } } +/* + * return true if attr contains default gw extended community + */ +uint8_t bgp_attr_default_gw(struct attr *attr) +{ + struct ecommunity *ecom; + int i; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return 0; + + /* If there is a default gw extendd community return true otherwise + * return 0 */ + for (i = 0; i < ecom->size; i++) { + u_char *pnt; + u_char type, sub_type; + + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + + if ((type == ECOMMUNITY_ENCODE_OPAQUE + && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) + return 1; + } + + return 0; +} + /* * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 8b55cb3002..a211da8d2f 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -62,5 +62,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, u_char *sticky); +extern uint8_t bgp_attr_default_gw(struct attr *attr); #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ 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_ecommunity.c b/bgpd/bgp_ecommunity.c index 9caf38d569..7dafde51a1 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -690,6 +690,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) tunneltype = ntohs(tunneltype); len = sprintf(str_buf + str_pnt, "ET:%d", tunneltype); + } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) { + len = sprintf(str_buf + str_pnt, + "Default Gateway"); } else unk_ecom = 1; } else if (type == ECOMMUNITY_ENCODE_EVPN) { 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; - 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; @@ -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; } diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 9400916845..a8dcbc112b 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -34,11 +34,33 @@ 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, + struct prefix *p, + struct attr *src_attr, afi_t afi, safi_t safi); extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, - struct bgp_node *rn, + struct prefix *p, afi_t afi, safi_t safi); extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); @@ -46,11 +68,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 2d52e1995d..cc0ec82344 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -65,6 +65,9 @@ struct bgpevpn { /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/ u_int8_t advertise_gw_macip; + /* Flag to indicate if we are advertising subnet for this VNI */ + u_int8_t advertise_subnet; + /* Id for deriving the RD automatically for this VNI */ u_int16_t rd_id; @@ -228,26 +231,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) { @@ -257,6 +240,13 @@ static inline void encode_rmac_extcomm(struct ecommunity_val *eval, memcpy(&eval->val[2], rmac, ETH_ALEN); } +static inline void encode_default_gw_extcomm(struct ecommunity_val *eval) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE; + eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW; +} + static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq, struct ecommunity_val *eval) { diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index b463896c49..bd42ccdecf 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -331,10 +331,88 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n"); vty_out(vty, "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n"); - vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n"); + vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n"); + vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n"); vty_out(vty, "%s", ri_header); } +static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, + json_object *json) +{ + char buf1[INET6_ADDRSTRLEN]; + char *ecom_str; + struct listnode *node, *nnode; + struct ecommunity *ecom; + json_object *json_import_rtl = NULL; + json_object *json_export_rtl = NULL; + + json_import_rtl = json_export_rtl = 0; + + if (json) { + json_import_rtl = json_object_new_array(); + json_export_rtl = json_object_new_array(); + json_object_int_add(json, "vni", bgp_vrf->l3vni); + json_object_string_add(json, "type", "L3"); + json_object_string_add(json, "kernelFlag", "Yes"); + json_object_string_add( + json, "rd", + prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN)); + json_object_string_add(json, "originatorIp", + inet_ntoa(bgp_vrf->originator_ip)); + json_object_string_add(json, "advertiseGatewayMacip", "n/a"); + } else { + vty_out(vty, "VNI: %d", bgp_vrf->l3vni); + vty_out(vty, " (known to the kernel)"); + vty_out(vty, "\n"); + + vty_out(vty, " Type: %s\n", "L3"); + vty_out(vty, " Tenant VRF: %s\n", + vrf_id_to_name(bgp_vrf->vrf_id)); + vty_out(vty, " RD: %s\n", + prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN)); + vty_out(vty, " Originator IP: %s\n", + inet_ntoa(bgp_vrf->originator_ip)); + vty_out(vty, " Advertise-gw-macip : %s\n", "n/a"); + } + + if (!json) + vty_out(vty, " Import Route Target:\n"); + + for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) { + ecom_str = ecommunity_ecom2str(ecom, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (json) + json_object_array_add(json_import_rtl, + json_object_new_string(ecom_str)); + else + vty_out(vty, " %s\n", ecom_str); + + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); + } + + if (json) + json_object_object_add(json, "importRts", json_import_rtl); + else + vty_out(vty, " Export Route Target:\n"); + + for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) { + ecom_str = ecommunity_ecom2str(ecom, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (json) + json_object_array_add(json_export_rtl, + json_object_new_string(ecom_str)); + else + vty_out(vty, " %s\n", ecom_str); + + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); + } + + if (json) + json_object_object_add(json, "exportRts", json_export_rtl); +} + static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) { char buf1[RD_ADDRSTRLEN]; @@ -348,6 +426,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) json_import_rtl = json_object_new_array(); json_export_rtl = json_object_new_array(); json_object_int_add(json, "vni", vpn->vni); + json_object_string_add(json, "type", "L2"); json_object_string_add(json, "kernelFlag", is_vni_live(vpn) ? "Yes" : "No"); json_object_string_add( @@ -363,6 +442,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) vty_out(vty, " (known to the kernel)"); vty_out(vty, "\n"); + vty_out(vty, " Type: %s\n", "L2"); vty_out(vty, " Tenant-Vrf: %s\n", vrf_id_to_name(vpn->tenant_vrf_id)); vty_out(vty, " RD: %s\n", @@ -570,6 +650,110 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg) json_object_object_add(json, vni_str, json_vni); } +static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, + json_object *json) +{ + json_object *json_vni; + json_object *json_import_rtl; + json_object *json_export_rtl; + char buf1[10]; + char buf2[INET6_ADDRSTRLEN]; + char rt_buf[25]; + char *ecom_str; + struct listnode *node, *nnode; + struct ecommunity *ecom; + + if (!bgp->l3vni) + return; + + if (json) { + json_vni = json_object_new_object(); + json_import_rtl = json_object_new_array(); + json_export_rtl = json_object_new_array(); + } + + /* if an l3vni is present in bgp it is live */ + buf1[0] = '\0'; + sprintf(buf1, "*"); + + if (json) { + json_object_int_add(json_vni, "vni", bgp->l3vni); + json_object_string_add(json_vni, "type", "L3"); + json_object_string_add(json_vni, "inKernel", "True"); + json_object_string_add(json_vni, "originatorIp", + inet_ntoa(bgp->originator_ip)); + json_object_string_add( + json_vni, "rd", + prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN)); + } else { + vty_out(vty, "%-1s %-10u %-4s %-21s", + buf1, bgp->l3vni, "L3", + prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN)); + } + + for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) { + ecom_str = ecommunity_ecom2str(ecom, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (json) { + json_object_array_add(json_import_rtl, + json_object_new_string(ecom_str)); + } else { + if (listcount(bgp->vrf_import_rtl) > 1) + sprintf(rt_buf, "%s, ...", ecom_str); + else + sprintf(rt_buf, "%s", ecom_str); + vty_out(vty, " %-25s", rt_buf); + } + + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); + + /* If there are multiple import RTs we break here and show only + * one */ + if (!json) + break; + } + + if (json) + json_object_object_add(json_vni, "importRTs", json_import_rtl); + + for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) { + ecom_str = ecommunity_ecom2str(ecom, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + + if (json) { + json_object_array_add(json_export_rtl, + json_object_new_string(ecom_str)); + } else { + if (listcount(bgp->vrf_export_rtl) > 1) + sprintf(rt_buf, "%s, ...", ecom_str); + else + sprintf(rt_buf, "%s", ecom_str); + vty_out(vty, " %-25s", rt_buf); + } + + XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); + + /* If there are multiple export RTs we break here and show only + * one */ + if (!json) + break; + } + + if (!json) + vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id)); + + if (json) { + char vni_str[VNI_STR_LEN]; + + json_object_object_add(json_vni, "exportRTs", json_export_rtl); + snprintf(vni_str, VNI_STR_LEN, "%u", bgp->l3vni); + json_object_object_add(json, vni_str, json_vni); + } else { + vty_out(vty, "\n"); + } +} + static void show_vni_entry(struct hash_backet *backet, void *args[]) { struct vty *vty; @@ -600,16 +784,19 @@ static void show_vni_entry(struct hash_backet *backet, void *args[]) if (json) { json_object_int_add(json_vni, "vni", vpn->vni); + json_object_string_add(json_vni, "type", "L2"); json_object_string_add(json_vni, "inKernel", is_vni_live(vpn) ? "True" : "False"); json_object_string_add(json_vni, "originatorIp", inet_ntoa(vpn->originator_ip)); + json_object_string_add(json_vni, "originatorIp", + inet_ntoa(vpn->originator_ip)); json_object_string_add( json_vni, "rd", prefix_rd2str(&vpn->prd, buf2, sizeof(buf2))); } else { - vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni, - inet_ntoa(vpn->originator_ip), + vty_out(vty, "%-1s %-10u %-4s %-21s", + buf1, vpn->vni, "L2", prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN)); } @@ -1982,7 +2169,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n"); vty_out(vty, - "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n"); + "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n"); rd_header = 0; } @@ -2181,10 +2368,26 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni, json_object *json) { + u_char found = 0; struct bgpevpn *vpn; vpn = bgp_evpn_lookup_vni(bgp, vni); - if (!vpn) { + if (vpn) { + found = 1; + display_vni(vty, vpn, json); + } else { + struct bgp *bgp_temp; + struct listnode *node = NULL; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) { + if (bgp_temp->l3vni == vni) { + found = 1; + display_l3vni(vty, bgp_temp, json); + } + } + } + + if (!found) { if (json) { vty_out(vty, "{}\n"); } else { @@ -2192,8 +2395,6 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni, return; } } - - display_vni(vty, vpn, json); } /* @@ -2202,28 +2403,29 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni, static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, json_object *json) { - u_int32_t num_vnis; void *args[2]; + struct bgp *bgp_temp = NULL; + struct listnode *node; - num_vnis = hashcount(bgp->vnihash); - if (!num_vnis) - return; - if (json) { - json_object_int_add(json, "numVnis", num_vnis); - } else { - vty_out(vty, "Number of VNIs: %u\n", num_vnis); + if (!json) { vty_out(vty, "Flags: * - Kernel\n"); - vty_out(vty, " %-10s %-15s %-21s %-25s %-25s %-37s\n", "VNI", - "Orig IP", "RD", "Import RT", - "Export RT", "Tenant-Vrf"); + vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI", + "Type", "RD", "Import RT", + "Export RT", "Tenant VRF"); } + /* print all L2 VNIS */ args[0] = vty; args[1] = json; hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, void *))show_vni_entry, args); + + /* print all L3 VNIs */ + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) + show_l3vni_entry(vty, bgp_temp, json); + } /* @@ -2271,6 +2473,32 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp, return; } +/* + * evpn - enable advertisement of default g/w + */ +static void evpn_set_advertise_subnet(struct bgp *bgp, + struct bgpevpn *vpn) +{ + if (vpn->advertise_subnet) + return; + + vpn->advertise_subnet = 1; + bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni); +} + +/* + * evpn - disable advertisement of default g/w + */ +static void evpn_unset_advertise_subnet(struct bgp *bgp, + struct bgpevpn *vpn) +{ + if (!vpn->advertise_subnet) + return; + + vpn->advertise_subnet = 0; + bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni); +} + /* * EVPN (VNI advertisement) enabled. Register with zebra. */ @@ -2330,6 +2558,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) if (vpn->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (vpn->advertise_subnet) + vty_out(vty, " advertise-subnet\n"); + vty_out(vty, " exit-vni\n"); } } @@ -2440,6 +2671,56 @@ DEFUN (no_bgp_evpn_advertise_all_vni, return CMD_SUCCESS; } +DEFUN (bgp_evpn_advertise_vni_subnet, + bgp_evpn_advertise_vni_subnet_cmd, + "advertise-subnet", + "Advertise the subnet corresponding to VNI\n") +{ + struct bgp *bgp_vrf = NULL; + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id); + if (!bgp_vrf) + return CMD_WARNING; + + if (!(advertise_type5_routes(bgp_vrf, AFI_IP) || + advertise_type5_routes(bgp_vrf, AFI_IP6))) { + vty_out(vty, + "%%Please enable ip prefix advertisement under l2vpn evpn in %s", + vrf_id_to_name(bgp_vrf->vrf_id)); + return CMD_WARNING; + } + + evpn_set_advertise_subnet(bgp, vpn); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_advertise_vni_subnet, + no_bgp_evpn_advertise_vni_subnet_cmd, + "no advertise-subnet", + NO_STR + "Advertise All local VNIs\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + evpn_unset_advertise_subnet(bgp, vpn); + return CMD_SUCCESS; +} + DEFUN (bgp_evpn_advertise_type5, bgp_evpn_advertise_type5_cmd, "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR, @@ -2563,16 +2844,21 @@ DEFUN(show_bgp_l2vpn_evpn_vni, "VNI number\n" JSON_STR) { - struct bgp *bgp; + struct bgp *bgp_def; vni_t vni; int idx = 0; u_char uj = 0; json_object *json = NULL; + u_int32_t num_l2vnis = 0; + u_int32_t num_l3vnis = 0; + uint32_t num_vnis = 0; + struct listnode *node = NULL; + struct bgp *bgp_temp = NULL; uj = use_json(argc, argv); - bgp = bgp_get_default(); - if (!bgp) + bgp_def = bgp_get_default(); + if (!bgp_def) return CMD_WARNING; if (!argv_find(argv, argc, "evpn", &idx)) @@ -2582,26 +2868,36 @@ DEFUN(show_bgp_l2vpn_evpn_vni, json = json_object_new_object(); if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) { + + num_l2vnis = hashcount(bgp_def->vnihash); + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) { + if (bgp_temp->l3vni) + num_l3vnis++; + } + num_vnis = num_l2vnis + num_l3vnis; if (uj) { json_object_string_add(json, "advertiseGatewayMacip", - bgp->advertise_gw_macip + bgp_def->advertise_gw_macip ? "Enabled" : "Disabled"); json_object_string_add(json, "advertiseAllVnis", is_evpn_enabled() ? "Enabled" : "Disabled"); + json_object_int_add(json, "numVnis", num_vnis); + json_object_int_add(json, "numL2Vnis", num_l2vnis); + json_object_int_add(json, "numL3Vnis", num_l3vnis); } else { vty_out(vty, "Advertise Gateway Macip: %s\n", - bgp->advertise_gw_macip ? "Enabled" + bgp_def->advertise_gw_macip ? "Enabled" : "Disabled"); - - /* Display all VNIs */ vty_out(vty, "Advertise All VNI flag: %s\n", is_evpn_enabled() ? "Enabled" : "Disabled"); + vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis); + vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis); } - - evpn_show_all_vnis(vty, bgp, json); + evpn_show_all_vnis(vty, bgp_def, json); } else { int vni_idx = 0; @@ -2610,7 +2906,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni, /* Display specific VNI */ vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10); - evpn_show_vni(vty, bgp, vni, json); + evpn_show_vni(vty, bgp_def, vni, json); } if (uj) { @@ -2644,7 +2940,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, */ DEFUN(show_bgp_l2vpn_evpn_route, show_bgp_l2vpn_evpn_route_cmd, - "show bgp l2vpn evpn route [type ] [json]", + "show bgp l2vpn evpn route [type ] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -2653,6 +2949,7 @@ DEFUN(show_bgp_l2vpn_evpn_route, "Specify Route type\n" "MAC-IP (Type-2) route\n" "Multicast (Type-3) route\n" + "Prefix route\n" JSON_STR) { struct bgp *bgp; @@ -2677,6 +2974,8 @@ DEFUN(show_bgp_l2vpn_evpn_route, type = BGP_EVPN_MAC_IP_ROUTE; else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; + else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0) + type = BGP_EVPN_IP_PREFIX_ROUTE; else return CMD_WARNING; } @@ -2688,7 +2987,6 @@ DEFUN(show_bgp_l2vpn_evpn_route, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } - return CMD_SUCCESS; } @@ -2697,7 +2995,7 @@ DEFUN(show_bgp_l2vpn_evpn_route, */ DEFUN(show_bgp_l2vpn_evpn_route_rd, show_bgp_l2vpn_evpn_route_rd_cmd, - "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type ] [json]", + "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type ] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -2708,6 +3006,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, "Specify Route type\n" "MAC-IP (Type-2) route\n" "Multicast (Type-3) route\n" + "Prefix route\n" JSON_STR) { struct bgp *bgp; @@ -2745,6 +3044,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, type = BGP_EVPN_MAC_IP_ROUTE; else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; + else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0) + type = BGP_EVPN_IP_PREFIX_ROUTE; else return CMD_WARNING; } @@ -3544,13 +3845,12 @@ static int bgp_evpn_rt_matches_existing(struct list *rtl, /* display L3VNI related info for a VRF instance */ DEFUN (show_bgp_vrf_l3vni_info, show_bgp_vrf_l3vni_info_cmd, - "show bgp vrf VRFNAME l3vni info [json]", + "show bgp vrf VRFNAME vni [json]", SHOW_STR BGP_STR "show bgp vrf\n" "VRF Name\n" "L3-VNI\n" - "L3-VNI info\n" JSON_STR) { char buf[ETHER_ADDR_STRLEN]; @@ -4118,5 +4418,8 @@ void bgp_ethernetvpn_init(void) &bgp_evpn_advertise_default_gw_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_advertise_default_gw_vni_cmd); + install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd); + install_element(BGP_EVPN_VNI_NODE, + &no_bgp_evpn_advertise_vni_subnet_cmd); #endif } 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..36e0c92482 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", @@ -2225,9 +2226,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (new_select) - bgp_evpn_advertise_type5_route(bgp, rn, afi, safi); + bgp_evpn_advertise_type5_route(bgp, &rn->p, + new_select->attr, + afi, safi); else if (old_select) - bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi); + bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } /* Clear any route change flags. */ @@ -2670,7 +2673,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 +2685,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 +2702,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 +2826,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 +2837,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 +2863,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 +2890,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 +2904,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 +2996,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 +3138,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 +3150,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 +3257,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 +3293,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 +3330,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 +3351,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 +3363,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 +3490,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 +4054,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 +4371,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); @@ -4443,7 +4472,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, ri->uptime = bgp_clock(); #if ENABLE_BGP_VNC if (ri->extra) - label = decode_label(&ri->extra->label); + label = decode_label(&ri->extra->label[0]); #endif /* Process change. */ @@ -4466,7 +4495,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 +6745,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 +7083,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 +7725,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 fc15720ebc..2d4034d77d 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_vty.c b/bgpd/bgp_vty.c index d30b057cbc..4a8eeb9121 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6126,8 +6126,10 @@ DEFUN_NOSH (address_family_ipv4_safi, VTY_DECLVAR_CONTEXT(bgp, bgp); safi_t safi = bgp_vty_safi_from_str(argv[2]->text); if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT && - safi != SAFI_UNICAST && safi != SAFI_MULTICAST) { - vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n"); + safi != SAFI_UNICAST && safi != SAFI_MULTICAST + && safi != SAFI_EVPN) { + vty_out(vty, + "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n"); return CMD_WARNING_CONFIG_FAILED; } vty->node = bgp_node_type(AFI_IP, safi); @@ -6148,8 +6150,10 @@ DEFUN_NOSH (address_family_ipv6_safi, VTY_DECLVAR_CONTEXT(bgp, bgp); safi_t safi = bgp_vty_safi_from_str(argv[2]->text); if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT && - safi != SAFI_UNICAST && safi != SAFI_MULTICAST) { - vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n"); + safi != SAFI_UNICAST && safi != SAFI_MULTICAST + && safi != SAFI_EVPN) { + vty_out(vty, + "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n"); return CMD_WARNING_CONFIG_FAILED; } vty->node = bgp_node_type(AFI_IP6, safi); @@ -6191,10 +6195,6 @@ DEFUN_NOSH (address_family_evpn, "Address Family modifier\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { - vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n"); - return CMD_WARNING_CONFIG_FAILED; - } vty->node = BGP_EVPN_NODE; return CMD_SUCCESS; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7f7d746256..e0bd74a206 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; @@ -1634,6 +1635,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer) zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0); } +int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni) +{ + struct stream *s = NULL; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_ADVERTISE_SUBNET, bgp->vrf_id); + stream_putc(s, advertise); + stream_put3(s, vni); + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) { struct stream *s = NULL; @@ -1820,6 +1844,55 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); } +static void bgp_zebra_process_local_ip_prefix(int cmd, + struct zclient *zclient, + zebra_size_t length, + vrf_id_t vrf_id) +{ + struct stream *s = NULL; + struct bgp *bgp_vrf = NULL; + struct prefix p; + char buf[PREFIX_STRLEN]; + + memset(&p, 0, sizeof(struct prefix)); + s = zclient->ibuf; + stream_get(&p, s, sizeof(struct prefix)); + + bgp_vrf = bgp_lookup_by_vrf_id(vrf_id); + if (!bgp_vrf) + return; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Recv prefix %s %s on vrf %s", + prefix2str(&p, buf, sizeof(buf)), + (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL", + vrf_id_to_name(vrf_id)); + + if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) { + + if (p.family == AF_INET) + return bgp_evpn_advertise_type5_route(bgp_vrf, &p, + NULL, + AFI_IP, + SAFI_UNICAST); + else + return bgp_evpn_advertise_type5_route(bgp_vrf, &p, + NULL, + AFI_IP6, + SAFI_UNICAST); + + } else { + if (p.family == AF_INET) + return bgp_evpn_withdraw_type5_route(bgp_vrf, &p, + AFI_IP, + SAFI_UNICAST); + else + return bgp_evpn_withdraw_type5_route(bgp_vrf, &p, + AFI_IP6, + SAFI_UNICAST); + } +} + extern struct zebra_privs_t bgpd_privs; void bgp_zebra_init(struct thread_master *master) @@ -1852,6 +1925,8 @@ void bgp_zebra_init(struct thread_master *master) zclient->local_macip_del = bgp_zebra_process_local_macip; zclient->local_l3vni_add = bgp_zebra_process_local_l3vni; zclient->local_l3vni_del = bgp_zebra_process_local_l3vni; + zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix; + zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix; } void bgp_zebra_destroy(void) diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 7d37864f44..da5160bc16 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -58,7 +58,8 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t, vrf_id_t); extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t, vrf_id_t); - +extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, + vni_t vni); extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t); extern int bgp_zebra_advertise_all_vni(struct bgp *, int); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 95666143a5..9d169eed32 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1083,7 +1083,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ /* save backref to rfapi handle */ assert(bgp_info_extra_get(new)); new->extra->vnc.export.rfapi_handle = (void *)rfd; - encode_label(label_val, &new->extra->label); + encode_label(label_val, &new->extra->label[0]); /* debug */ diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 8727c5d5ea..e1508dbd83 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -521,7 +521,7 @@ static struct bgp_info *rfapiBgpInfoCreate(struct attr *attr, struct peer *peer, rfapi_time(&new->extra->vnc.import.create_time); } if (label) - encode_label(*label, &new->extra->label); + encode_label(*label, &new->extra->label[0]); new->type = type; new->sub_type = sub_type; new->peer = peer; @@ -1338,7 +1338,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bi->extra->label); + vo->v.l2addr.label = decode_label(&bi->extra->label[0]); new->vn_options = vo; @@ -4242,7 +4242,7 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp, if (bi->extra) label = decode_label( - &bi->extra->label); + &bi->extra->label[0]); (*rfapiBgpInfoFilteredImportFunction( safi))( it, /* which import table */ diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index bd79518bfd..271c748510 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -697,7 +697,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri, vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bi->extra->label); + vo->v.l2addr.label = decode_label(&bi->extra->label[0]); rfapi_vn_options_free( ri->vn_options); /* maybe free old version */ diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 15d27b3961..28d068cc57 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -432,7 +432,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p, } if (bi->extra != NULL) - vty_out(vty, " label=%u", decode_label(&bi->extra->label)); + vty_out(vty, " label=%u", decode_label(&bi->extra->label[0])); if (!rfapiGetVncLifetime(bi->attr, &lifetime)) { vty_out(vty, " life=%d", lifetime); @@ -1068,7 +1068,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, BUFSIZ)); if (bi->extra) { - u_int32_t l = decode_label(&bi->extra->label); + u_int32_t l = decode_label(&bi->extra->label[0]); snprintf(buf_vn, BUFSIZ, "Label: %d", l); } else /* should never happen */ { @@ -1181,7 +1181,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } } if (tun_type != BGP_ENCAP_TYPE_MPLS && bi->extra) { - u_int32_t l = decode_label(&bi->extra->label); + u_int32_t l = decode_label(&bi->extra->label[0]); if (!MPLS_LABEL_IS_NULL(l)) { fp(out, " Label: %d", l); if (nlines == 1) diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index d4921ce40a..e88dd9399c 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); } @@ -398,7 +398,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct route_node *rn, NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not used for unicast */ + NULL, 0, NULL); /* tag not used for unicast */ } static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi) @@ -498,7 +498,7 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi) ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, + NULL, 0, NULL); /* tag not used for unicast */ } } @@ -880,7 +880,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not used for unicast */ + NULL, 0, NULL); /* tag not used for unicast */ /* * yuck! * - but consistent with rest of function @@ -909,7 +909,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not used for unicast */ + NULL, 0, NULL); /* tag not used for unicast */ } } } @@ -1048,7 +1048,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) unicast */ NULL, /* tag not used for unicast */ - 0, NULL); /* EVPN not used */ + 0, 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); } @@ -1142,7 +1142,7 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not + NULL, 0, NULL); /* tag not used for unicast */ } @@ -1260,7 +1260,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ - 0, NULL); /* EVPN not used */ + 0, 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); @@ -1374,7 +1374,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, + NULL, 0, NULL); /* tag not used for unicast */ return; } @@ -1496,7 +1496,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct route_table *rt, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not + NULL, 0, NULL); /* tag not used for unicast, EVPN @@ -1719,7 +1719,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi, afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast, EVPN neither */ - 0, NULL); /* EVPN not used */ + 0, 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); } @@ -1734,7 +1734,7 @@ static int vncExportWithdrawTimer(struct thread *t) NULL, /* attr, ignored */ family2afi(eti->node->p.family), SAFI_UNICAST, eti->type, eti->subtype, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not used for unicast, EVPN neither */ + NULL, 0, NULL); /* tag not used for unicast, EVPN neither */ /* * Free the eti @@ -1965,7 +1965,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) NULL, /* tag not used for unicast, EVPN neither */ - 0, NULL); /* EVPN not used */ + 0, 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); } } @@ -2026,7 +2026,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, NULL); /* tag not used for + NULL, 0, NULL); /* tag not used for unicast, EVPN neither */ } diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index f7e86123b4..cfa4c599f2 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -495,7 +495,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( ecommunity_merge(new_ecom, bi->attr->ecommunity); if (bi->extra) - label = decode_label(&bi->extra->label); + label = decode_label(&bi->extra->label[0]); add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN, prefix, /* unicast route prefix */ @@ -1783,7 +1783,7 @@ static void vnc_import_bgp_exterior_add_route_it( prd = &bi_interior->extra->vnc.import .rd; label = decode_label( - &bi_interior->extra->label); + &bi_interior->extra->label[0]); } else prd = NULL; @@ -1958,7 +1958,7 @@ void vnc_import_bgp_exterior_del_route( prd = &bi_interior->extra->vnc.import .rd; label = decode_label( - &bi_interior->extra->label); + &bi_interior->extra->label[0]); } else prd = NULL; @@ -2113,7 +2113,7 @@ void vnc_import_bgp_exterior_add_route_interior( if (bi_interior->extra) { prd = &bi_interior->extra->vnc.import.rd; label = decode_label( - &bi_interior->extra->label); + &bi_interior->extra->label[0]); } else prd = NULL; @@ -2226,7 +2226,7 @@ void vnc_import_bgp_exterior_add_route_interior( if (bi->extra) { prd = &bi->extra->vnc.import.rd; label = decode_label( - &bi->extra->label); + &bi->extra->label[0]); } else prd = NULL; @@ -2248,7 +2248,7 @@ void vnc_import_bgp_exterior_add_route_interior( prd = &bi_interior->extra->vnc.import .rd; label = decode_label( - &bi_interior->extra->label); + &bi_interior->extra->label[0]); } else prd = NULL; @@ -2369,7 +2369,7 @@ void vnc_import_bgp_exterior_add_route_interior( if (bi_interior->extra) { prd = &bi_interior->extra->vnc.import.rd; label = decode_label( - &bi_interior->extra->label); + &bi_interior->extra->label[0]); } else prd = NULL; @@ -2480,7 +2480,7 @@ void vnc_import_bgp_exterior_del_route_interior( if (bi_interior->extra) { prd = &bi_interior->extra->vnc.import.rd; - label = decode_label(&bi_interior->extra->label); + label = decode_label(&bi_interior->extra->label[0]); } else prd = NULL; @@ -2556,7 +2556,8 @@ void vnc_import_bgp_exterior_del_route_interior( if (bi->extra) { prd = &bi->extra->vnc.import.rd; - label = decode_label(&bi->extra->label); + label = decode_label( + &bi->extra->label[0]); } else prd = NULL; diff --git a/lib/log.c b/lib/log.c index bf65ac7c7d..66be533e84 100644 --- a/lib/log.c +++ b/lib/log.c @@ -943,6 +943,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), + DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET), DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_DEL), DESC_ENTRY(ZEBRA_L3VNI_ADD), @@ -951,6 +952,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL), DESC_ENTRY(ZEBRA_MACIP_ADD), DESC_ENTRY(ZEBRA_MACIP_DEL), + DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_ADD), + DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_DEL), DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD), DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL), DESC_ENTRY(ZEBRA_PW_ADD), diff --git a/lib/vrf.c b/lib/vrf.c index 2fa3a9c0ef..2e15fa2f5c 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -141,7 +141,9 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) return vrf; } -/* Delete a VRF. This is called in vrf_terminate(). */ +/* Delete a VRF. This is called when the underlying VRF goes away, a + * pre-configured VRF is deleted or when shutting down (vrf_terminate()). + */ void vrf_delete(struct vrf *vrf) { if (debug_vrf) @@ -150,6 +152,23 @@ void vrf_delete(struct vrf *vrf) if (vrf_is_enabled(vrf)) vrf_disable(vrf); + /* If the VRF is user configured, it'll stick around, just remove + * the ID mapping. Interfaces assigned to this VRF should've been + * removed already as part of the VRF going down. + */ + if (vrf_is_user_cfged(vrf)) { + if (vrf->vrf_id != VRF_UNKNOWN) { + /* Delete any VRF interfaces - should be only + * the VRF itself, other interfaces should've + * been moved out of the VRF. + */ + if_terminate(vrf); + RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); + vrf->vrf_id = VRF_UNKNOWN; + } + return; + } + if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook)(vrf); @@ -172,14 +191,6 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id) return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf)); } -/* - * Check whether the VRF is enabled. - */ -static int vrf_is_enabled(struct vrf *vrf) -{ - return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE); -} - /* * Enable a VRF - that is, let the VRF be ready to use. * The VRF_ENABLE_HOOK callback will be called to inform @@ -408,10 +419,16 @@ void vrf_terminate(void) zlog_debug("%s: Shutting down vrf subsystem", __PRETTY_FUNCTION__); - while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) + while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) { + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); vrf_delete(vrf); - while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) + } + while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) { + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); vrf_delete(vrf); + } } /* Create a socket for the VRF. */ @@ -473,6 +490,8 @@ DEFUN_NOSH (no_vrf, return CMD_WARNING_CONFIG_FAILED; } + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrfp->status, VRF_CONFIGURED); vrf_delete(vrfp); return CMD_SUCCESS; diff --git a/lib/vrf.h b/lib/vrf.h index 7e625769e7..99c048c702 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -75,7 +75,8 @@ struct vrf { /* Zebra internal VRF status */ u_char status; -#define VRF_ACTIVE (1 << 0) +#define VRF_ACTIVE (1 << 0) /* VRF is up in kernel */ +#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */ /* Interfaces belonging to this VRF */ struct if_name_head ifaces_by_name; @@ -119,6 +120,32 @@ extern vrf_id_t vrf_name_to_id(const char *); (V) = vrf->vrf_id; \ } while (0) +/* + * Check whether the VRF is enabled. + */ +static inline int vrf_is_enabled(struct vrf *vrf) +{ + return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE); +} + +/* check if the vrf is user configured */ +static inline int vrf_is_user_cfged(struct vrf *vrf) +{ + return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED); +} + +/* Mark that VRF has user configuration */ +static inline void vrf_set_user_cfged(struct vrf *vrf) +{ + SET_FLAG(vrf->status, VRF_CONFIGURED); +} + +/* Mark that VRF no longer has any user configuration */ +static inline void vrf_reset_user_cfged(struct vrf *vrf) +{ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); +} + /* * Utilities to obtain the user data */ diff --git a/lib/zclient.c b/lib/zclient.c index 6f770c66e4..0c29b523bf 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2333,6 +2333,16 @@ static int zclient_read(struct thread *thread) (*zclient->local_macip_del)(command, zclient, length, vrf_id); break; + case ZEBRA_IP_PREFIX_ROUTE_ADD: + if (zclient->local_ip_prefix_add) + (*zclient->local_ip_prefix_add)(command, zclient, + length, vrf_id); + break; + case ZEBRA_IP_PREFIX_ROUTE_DEL: + if (zclient->local_ip_prefix_del) + (*zclient->local_ip_prefix_del)(command, zclient, + length, vrf_id); + break; case ZEBRA_PW_STATUS_UPDATE: if (zclient->pw_status_update) (*zclient->pw_status_update)(command, zclient, length, diff --git a/lib/zclient.h b/lib/zclient.h index bd4d32d2bd..5c7c5d6d5b 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -109,6 +109,7 @@ typedef enum { ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, ZEBRA_ADVERTISE_DEFAULT_GW, + ZEBRA_ADVERTISE_SUBNET, ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_VNI_ADD, ZEBRA_VNI_DEL, @@ -118,6 +119,8 @@ typedef enum { ZEBRA_REMOTE_VTEP_DEL, ZEBRA_MACIP_ADD, ZEBRA_MACIP_DEL, + ZEBRA_IP_PREFIX_ROUTE_ADD, + ZEBRA_IP_PREFIX_ROUTE_DEL, ZEBRA_REMOTE_MACIP_ADD, ZEBRA_REMOTE_MACIP_DEL, ZEBRA_PW_ADD, @@ -204,6 +207,8 @@ struct zclient { int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t); + void (*local_ip_prefix_add)(int, struct zclient *, uint16_t, vrf_id_t); + void (*local_ip_prefix_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); @@ -343,8 +348,8 @@ enum zapi_route_notify_owner { }; /* Zebra MAC types */ -#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/ -#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/ +#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ +#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ struct zclient_options { bool receive_notify; diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 138a446321..967f855fbc 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -352,13 +352,15 @@ void vtysh_config_dump(FILE *fp) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { for (ALL_LIST_ELEMENTS(master, node, nnode, config)) { - /* Don't print empty sections for interface/vrf. + /* Don't print empty sections for interface. * Route maps on the * other hand could have a legitimate empty * section at the end. + * VRF is handled in the backend, we could have + * "configured" VRFs with static routes which + * are not under the VRF node. */ - if ((config->index == INTERFACE_NODE - || config->index == VRF_NODE) + if (config->index == INTERFACE_NODE && list_isempty(config->line)) continue; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 61051ba87e..22c81b5784 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2875,6 +2875,16 @@ int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf) return 1; } +/* + * Called when VRF becomes inactive, cleans up information but keeps + * the table itself. + * NOTE: Currently supported only for default VRF. + */ +void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf) +{ + hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL); +} + /* * Called upon process exiting, need to delete LSP forwarding * entries from the kernel. diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 9d8ca34f82..27a4971691 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -384,6 +384,13 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, */ int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf); +/* + * Called when VRF becomes inactive, cleans up information but keeps + * the table itself. + * NOTE: Currently supported only for default VRF. + */ +void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf); + /* * Called upon process exiting, need to delete LSP forwarding * entries from the kernel. diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index b3b9c6d18a..c48a6f7bd8 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -41,6 +41,7 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) return dzns; } +/* Do global enable actions - open sockets, read kernel config etc. */ int zebra_ns_enable(ns_id_t ns_id, void **info) { struct zebra_ns *zns = (struct zebra_ns *)(*info); @@ -49,8 +50,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) rtadv_init(zns); #endif - zns->if_table = route_table_init(); - zebra_vxlan_ns_init(zns); kernel_init(zns); interface_list(zns); route_read(zns); @@ -79,8 +78,14 @@ int zebra_ns_init(void) ns_init(); + /* Do any needed per-NS data structure allocation. */ + dzns->if_table = route_table_init(); + zebra_vxlan_ns_init(dzns); + + /* Register zebra VRF callbacks, create and activate default VRF. */ zebra_vrf_init(); + /* Default NS is activated */ zebra_ns_enable(NS_DEFAULT, (void **)&dzns); return 0; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 246a7e7e4c..b9b3048486 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -41,6 +41,11 @@ extern struct zebra_t zebrad; +static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, + safi_t safi); +static void zebra_rnhtable_node_cleanup(struct route_table *table, + struct route_node *node); + /* VRF information update. */ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) { @@ -82,7 +87,7 @@ static int zebra_vrf_new(struct vrf *vrf) struct zebra_vrf *zvrf; if (IS_ZEBRA_DEBUG_EVENT) - zlog_info("ZVRF %s with id %u", vrf->name, vrf->vrf_id); + zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id); zvrf = zebra_vrf_alloc(); zvrf->zns = zebra_ns_lookup( @@ -101,14 +106,36 @@ static int zebra_vrf_enable(struct vrf *vrf) struct route_table *stable; struct route_node *rn; struct static_route *si; + struct route_table *table; struct interface *ifp; afi_t afi; safi_t safi; assert(zvrf); + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("VRF %s id %u is now active", + zvrf_name(zvrf), zvrf_id(zvrf)); + /* Inform clients that the VRF is now active. This is an + * add for the clients. + */ zebra_vrf_add_update(zvrf); + /* Allocate tables */ + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + zebra_vrf_table_create(zvrf, afi, safi); + + table = route_table_init(); + table->cleanup = zebra_rnhtable_node_cleanup; + zvrf->rnh_table[afi] = table; + + table = route_table_init(); + table->cleanup = zebra_rnhtable_node_cleanup; + zvrf->import_check_table[afi] = table; + } + + /* Install any static routes configured for this VRF. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { stable = zvrf->stable[afi][safi]; @@ -132,6 +159,9 @@ static int zebra_vrf_enable(struct vrf *vrf) } } + /* Kick off any VxLAN-EVPN processing. */ + zebra_vxlan_vrf_enable(zvrf); + return 0; } @@ -142,13 +172,19 @@ static int zebra_vrf_disable(struct vrf *vrf) struct route_table *stable; struct route_node *rn; struct static_route *si; + struct route_table *table; + struct interface *ifp; + u_int32_t table_id; afi_t afi; safi_t safi; + unsigned i; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("VRF %s id %u is now disabled.", zvrf_name(zvrf), - zvrf_id(zvrf)); + assert(zvrf); + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("VRF %s id %u is now inactive", + zvrf_name(zvrf), zvrf_id(zvrf)); + /* Uninstall any static routes configured for this VRF. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { stable = zvrf->stable[afi][safi]; @@ -161,6 +197,84 @@ static int zebra_vrf_disable(struct vrf *vrf) afi, safi, &rn->p, NULL, si); } + /* Stop any VxLAN-EVPN processing. */ + zebra_vxlan_vrf_disable(zvrf); + + /* Inform clients that the VRF is now inactive. This is a + * delete for the clients. + */ + zebra_vrf_delete_update(zvrf); + + /* If asked to retain routes, there's nothing more to do. */ + if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) + return 0; + + /* Remove all routes. */ + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + rib_close_table(zvrf->table[afi][safi]); + + if (vrf->vrf_id == VRF_DEFAULT) + for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; + table_id++) + if (zvrf->other_table[afi][table_id]) + rib_close_table(zvrf->other_table[afi][table_id]); + } + + /* Cleanup Vxlan, MPLS and PW tables. */ + zebra_vxlan_cleanup_tables(zvrf); + zebra_mpls_cleanup_tables(zvrf); + zebra_pw_exit(zvrf); + + /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */ + FOR_ALL_INTERFACES (vrf, ifp) + if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); + + /* clean-up work queues */ + for (i = 0; i < MQ_SIZE; i++) { + struct listnode *lnode, *nnode; + struct route_node *rnode; + rib_dest_t *dest; + + for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) { + dest = rib_dest_from_rnode(rnode); + if (dest && rib_dest_vrf(dest) == zvrf) { + route_unlock_node(rnode); + list_delete_node(zebrad.mq->subq[i], lnode); + zebrad.mq->size--; + } + } + } + + /* Cleanup (free) routing tables and NHT tables. */ + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + void *table_info; + + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + table = zvrf->table[afi][safi]; + table_info = table->info; + route_table_finish(table); + XFREE(MTYPE_RIB_TABLE_INFO, table_info); + zvrf->table[afi][safi] = NULL; + } + + if (vrf->vrf_id == VRF_DEFAULT) + for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; + table_id++) + if (zvrf->other_table[afi][table_id]) { + table = zvrf->other_table[afi][table_id]; + table_info = table->info; + route_table_finish(table); + XFREE(MTYPE_RIB_TABLE_INFO, table_info); + zvrf->other_table[afi][table_id] = NULL; + } + + route_table_finish(zvrf->rnh_table[afi]); + zvrf->rnh_table[afi] = NULL; + route_table_finish(zvrf->import_check_table[afi]); + zvrf->import_check_table[afi] = NULL; + } + return 0; } @@ -174,38 +288,9 @@ static int zebra_vrf_delete(struct vrf *vrf) unsigned i; assert(zvrf); - - zebra_vrf_delete_update(zvrf); - - /* uninstall everything */ - if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) { - struct interface *ifp; - - for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; - safi++) - rib_close_table(zvrf->table[afi][safi]); - - if (vrf->vrf_id == VRF_DEFAULT) - for (table_id = 0; - table_id < ZEBRA_KERNEL_TABLE_MAX; - table_id++) - if (zvrf->other_table[afi][table_id]) - rib_close_table( - zvrf->other_table - [afi] - [table_id]); - } - - /* Cleanup Vxlan table and update kernel */ - zebra_vxlan_close_tables(zvrf); - - zebra_mpls_close_tables(zvrf); - zebra_pw_exit(zvrf); - - FOR_ALL_INTERFACES (vrf, ifp) - if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); - } + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("VRF %s id %u deleted", + zvrf_name(zvrf), zvrf_id(zvrf)); /* clean-up work queues */ for (i = 0; i < MQ_SIZE; i++) { @@ -213,8 +298,7 @@ static int zebra_vrf_delete(struct vrf *vrf) struct route_node *rnode; rib_dest_t *dest; - for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, - rnode)) { + for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) { dest = rib_dest_from_rnode(rnode); if (dest && rib_dest_vrf(dest) == zvrf) { route_unlock_node(rnode); @@ -224,22 +308,27 @@ static int zebra_vrf_delete(struct vrf *vrf) } } + /* Free Vxlan and MPLS. */ + zebra_vxlan_close_tables(zvrf); + zebra_mpls_close_tables(zvrf); + /* release allocated memory */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { void *table_info; for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { table = zvrf->table[afi][safi]; - table_info = table->info; - route_table_finish(table); - XFREE(MTYPE_RIB_TABLE_INFO, table_info); + if (table) { + table_info = table->info; + route_table_finish(table); + XFREE(MTYPE_RIB_TABLE_INFO, table_info); + } table = zvrf->stable[afi][safi]; route_table_finish(table); } - for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; - table_id++) + for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++) if (zvrf->other_table[afi][table_id]) { table = zvrf->other_table[afi][table_id]; table_info = table->info; @@ -251,7 +340,7 @@ static int zebra_vrf_delete(struct vrf *vrf) route_table_finish(zvrf->import_check_table[afi]); } - /* cleanup evpn states for vrf */ + /* Cleanup EVPN states for vrf */ zebra_vxlan_vrf_delete(zvrf); list_delete_all_node(zvrf->rid_all_sorted_list); @@ -262,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf) return 0; } +/* Return if this VRF has any FRR configuration or not. + * IMPORTANT: This function needs to be updated when additional configuration + * is added for a VRF. + */ +int zebra_vrf_has_config(struct zebra_vrf *zvrf) +{ + afi_t afi; + safi_t safi; + struct route_table *stable; + + /* NOTE: This is a don't care for the default VRF, but we go through + * the motions to keep things consistent. + */ + /* Any static routes? */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + stable = zvrf->stable[afi][safi]; + if (!stable) + continue; + if (route_table_count(stable)) + return 1; + } + } + + /* EVPN L3-VNI? */ + if (zvrf->l3vni) + return 1; + + return 0; +} + /* Lookup the routing table in a VRF based on both VRF-Id and table-id. * NOTE: Table-id is relevant only in the Default VRF. */ @@ -354,9 +474,9 @@ struct zebra_vrf *zebra_vrf_alloc(void) zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf)); + /* Allocate table for static route configuration. */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { - zebra_vrf_table_create(zvrf, afi, safi); if (afi == AFI_IP6) table = srcdest_table_init(); else @@ -364,14 +484,6 @@ struct zebra_vrf *zebra_vrf_alloc(void) table->cleanup = zebra_stable_node_cleanup; zvrf->stable[afi][safi] = table; } - - table = route_table_init(); - table->cleanup = zebra_rnhtable_node_cleanup; - zvrf->rnh_table[afi] = table; - - table = route_table_init(); - table->cleanup = zebra_rnhtable_node_cleanup; - zvrf->import_check_table[afi] = table; } zebra_vxlan_init_tables(zvrf); @@ -477,16 +589,23 @@ static int vrf_config_write(struct vty *vty) if (!zvrf) continue; - if (vrf->vrf_id != VRF_DEFAULT) + if (zvrf_id(zvrf) == VRF_DEFAULT) { + if (zvrf->l3vni) + vty_out(vty, "vni %u\n", zvrf->l3vni); + vty_out(vty, "!\n"); + } + + if (vrf_is_user_cfged(vrf)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); + if (zvrf->l3vni) + vty_out(vty, " vni %u\n", zvrf->l3vni); + vty_out(vty, "!\n"); + } static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); - if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni) - vty_out(vty, " vni %u\n", zvrf->l3vni); - if (vrf->vrf_id != VRF_DEFAULT) vty_out(vty, "!\n"); } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index c7a0717ee8..fe7e77e8be 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -149,5 +149,6 @@ extern struct route_table *zebra_vrf_static_table(afi_t, safi_t, struct zebra_vrf *zvrf); extern struct route_table * zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, vrf_id_t vrf_id); +extern int zebra_vrf_has_config(struct zebra_vrf *zvrf); extern void zebra_vrf_init(void); #endif diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 62869b7eec..f8c9833854 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -231,13 +231,19 @@ static int zebra_static_route_leak(struct vty *vty, type = STATIC_IPV6_GATEWAY; } - if (!negate) + if (!negate) { static_add_route(afi, safi, type, &p, src_p, gatep, ifname, bh_type, tag, distance, zvrf, nh_zvrf, &snh_label); - else + /* Mark as having FRR configuration */ + vrf_set_user_cfged(zvrf->vrf); + } else { static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); + /* If no other FRR config for this VRF, mark accordingly. */ + if (!zebra_vrf_has_config(zvrf)) + vrf_reset_user_cfged(zvrf->vrf); + } return CMD_SUCCESS; } @@ -247,19 +253,39 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, const char *mask_str, const char *src_str, const char *gate_str, const char *ifname, const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_id_str, + const char *distance_str, const char *vrf_name, const char *label_str) { struct zebra_vrf *zvrf; + struct vrf *vrf; /* VRF id */ - zvrf = zebra_vrf_lookup_by_name(vrf_id_str); + zvrf = zebra_vrf_lookup_by_name(vrf_name); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); + /* When trying to delete, the VRF must exist. */ + if (negate && !zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf_name); return CMD_WARNING_CONFIG_FAILED; } + /* When trying to create, create the VRF if it doesn't exist. + * Note: The VRF isn't active until we hear about it from the kernel. + */ + if (!zvrf) { + vrf = vrf_get(VRF_UNKNOWN, vrf_name); + if (!vrf) { + vty_out(vty, "%% Could not create vrf %s\n", vrf_name); + return CMD_WARNING_CONFIG_FAILED; + } + zvrf = vrf->info; + if (!zvrf) { + vty_out(vty, "%% Could not create vrf-info %s\n", + vrf_name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Mark as having FRR configuration */ + vrf_set_user_cfged(vrf); + } return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi, negate, dest_str, mask_str, src_str, gate_str, ifname, flag_str, tag_str, @@ -2286,16 +2312,67 @@ DEFUN (show_vrf, else vty_out(vty, "id %u table %u", zvrf_id(zvrf), zvrf->table_id); + if (vrf_is_user_cfged(vrf)) + vty_out(vty, " (configured)"); vty_out(vty, "\n"); } return CMD_SUCCESS; } +DEFUN (default_vrf_vni_mapping, + default_vrf_vni_mapping_cmd, + "vni " CMD_VNI_RANGE, + "VNI corresponding to the DEFAULT VRF\n" + "VNI-ID\n") +{ + int ret = 0; + char err[ERR_STR_SZ]; + struct zebra_vrf *zvrf = NULL; + vni_t vni = strtoul(argv[1]->arg, NULL, 10); + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return CMD_WARNING; + + ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1); + if (ret != 0) { + vty_out(vty, "%s\n", err); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN (no_default_vrf_vni_mapping, + no_default_vrf_vni_mapping_cmd, + "no vni " CMD_VNI_RANGE, + NO_STR + "VNI corresponding to DEFAULT VRF\n" + "VNI-ID") +{ + int ret = 0; + char err[ERR_STR_SZ]; + vni_t vni = strtoul(argv[2]->arg, NULL, 10); + struct zebra_vrf *zvrf = NULL; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return CMD_WARNING; + + ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0); + if (ret != 0) { + vty_out(vty, "%s\n", err); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + DEFUN (vrf_vni_mapping, vrf_vni_mapping_cmd, "vni " CMD_VNI_RANGE, - "VNI\n" + "VNI corresponding to tenant VRF\n" "VNI-ID\n") { int ret = 0; @@ -2307,6 +2384,8 @@ DEFUN (vrf_vni_mapping, assert(vrf); assert(zvrf); + /* Mark as having FRR configuration */ + vrf_set_user_cfged(vrf); ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1); if (ret != 0) { vty_out(vty, "%s\n", err); @@ -2320,7 +2399,7 @@ DEFUN (no_vrf_vni_mapping, no_vrf_vni_mapping_cmd, "no vni " CMD_VNI_RANGE, NO_STR - "VNI\n" + "VNI corresponding to tenant VRF\n" "VNI-ID") { int ret = 0; @@ -2338,6 +2417,10 @@ DEFUN (no_vrf_vni_mapping, return CMD_WARNING; } + /* If no other FRR config for this VRF, mark accordingly. */ + if (!zebra_vrf_has_config(zvrf)) + vrf_reset_user_cfged(vrf); + return CMD_SUCCESS; } @@ -2361,29 +2444,16 @@ DEFUN (show_vrf_vni, json_vrfs = json_object_new_array(); } + if (!uj) + vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n", + "VRF", "VNI", "VxLAN IF", "L3-SVI", "State", "Rmac"); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; if (!zvrf) continue; - if (!zvrf->l3vni) - continue; - - if (!uj) { - vty_out(vty, "vrf: %s VNI: %u", - zvrf_name(zvrf), - zvrf->l3vni); - vty_out(vty, "\n"); - } else { - json_object *json_vrf = NULL; - - json_vrf = json_object_new_object(); - json_object_string_add(json_vrf, "vrf", - zvrf_name(zvrf)); - json_object_int_add(json_vrf, "l3vni", - zvrf->l3vni); - json_object_array_add(json_vrfs, json_vrf); - } + zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs); } if (uj) { @@ -2396,6 +2466,19 @@ DEFUN (show_vrf_vni, return CMD_SUCCESS; } +DEFUN (show_evpn_global, + show_evpn_global_cmd, + "show evpn [json]", + SHOW_STR + "EVPN\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + + zebra_vxlan_print_evpn(vty, uj); + return CMD_SUCCESS; +} + DEFUN (show_evpn_vni, show_evpn_vni_cmd, "show evpn vni [json]", @@ -2431,44 +2514,13 @@ DEFUN (show_evpn_vni_vni, return CMD_SUCCESS; } -DEFUN (show_evpn_l3vni, - show_evpn_l3vni_cmd, - "show evpn l3vni [json]", - SHOW_STR - "EVPN\n" - "L3 VNI\n" - JSON_STR) -{ - u_char uj = use_json(argc, argv); - - zebra_vxlan_print_l3vnis(vty, uj); - return CMD_SUCCESS; -} - -DEFUN (show_evpn_l3vni_vni, - show_evpn_l3vni_vni_cmd, - "show evpn l3vni " CMD_VNI_RANGE "[json]", - SHOW_STR - "EVPN\n" - "L3 VxLAN Network Identifier\n" - "VNI number\n" - JSON_STR) -{ - vni_t vni; - u_char uj = use_json(argc, argv); - - vni = strtoul(argv[3]->arg, NULL, 10); - zebra_vxlan_print_l3vni(vty, vni, uj); - return CMD_SUCCESS; -} - -DEFUN (show_evpn_rmac_l3vni_mac, - show_evpn_rmac_l3vni_mac_cmd, - "show evpn rmac l3vni " CMD_VNI_RANGE " mac WORD [json]", +DEFUN (show_evpn_rmac_vni_mac, + show_evpn_rmac_vni_mac_cmd, + "show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]", SHOW_STR "EVPN\n" "RMAC\n" - "L3-VNI\n" + "L3 VNI\n" "VNI number\n" "MAC\n" "mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n" @@ -2487,13 +2539,13 @@ DEFUN (show_evpn_rmac_l3vni_mac, return CMD_SUCCESS; } -DEFUN (show_evpn_rmac_l3vni, - show_evpn_rmac_l3vni_cmd, - "show evpn rmac l3vni " CMD_VNI_RANGE "[json]", +DEFUN (show_evpn_rmac_vni, + show_evpn_rmac_vni_cmd, + "show evpn rmac vni " CMD_VNI_RANGE "[json]", SHOW_STR "EVPN\n" "RMAC\n" - "L3-VNI\n" + "L3 VNI\n" "VNI number\n" JSON_STR) { @@ -2506,13 +2558,13 @@ DEFUN (show_evpn_rmac_l3vni, return CMD_SUCCESS; } -DEFUN (show_evpn_rmac_l3vni_all, - show_evpn_rmac_l3vni_all_cmd, - "show evpn rmac l3vni all [json]", +DEFUN (show_evpn_rmac_vni_all, + show_evpn_rmac_vni_all_cmd, + "show evpn rmac vni all [json]", SHOW_STR "EVPN\n" "RMAC addresses\n" - "L3-VNI\n" + "L3 VNI\n" "All VNIs\n" JSON_STR) { @@ -2523,13 +2575,13 @@ DEFUN (show_evpn_rmac_l3vni_all, return CMD_SUCCESS; } -DEFUN (show_evpn_nh_l3vni_ip, - show_evpn_nh_l3vni_ip_cmd, - "show evpn next-hops l3vni " CMD_VNI_RANGE " ip WORD [json]", +DEFUN (show_evpn_nh_vni_ip, + show_evpn_nh_vni_ip_cmd, + "show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]", SHOW_STR "EVPN\n" "Remote Vteps\n" - "L3-VNI\n" + "L3 VNI\n" "VNI number\n" "Ip address\n" "Host address (ipv4 or ipv6)\n" @@ -2550,13 +2602,13 @@ DEFUN (show_evpn_nh_l3vni_ip, return CMD_SUCCESS; } -DEFUN (show_evpn_nh_l3vni, - show_evpn_nh_l3vni_cmd, - "show evpn next-hops l3vni " CMD_VNI_RANGE "[json]", +DEFUN (show_evpn_nh_vni, + show_evpn_nh_vni_cmd, + "show evpn next-hops vni " CMD_VNI_RANGE "[json]", SHOW_STR "EVPN\n" "Remote Vteps\n" - "L3-VNI\n" + "L3 VNI\n" "VNI number\n" JSON_STR) { @@ -2569,13 +2621,13 @@ DEFUN (show_evpn_nh_l3vni, return CMD_SUCCESS; } -DEFUN (show_evpn_nh_l3vni_all, - show_evpn_nh_l3vni_all_cmd, - "show evpn next-hops l3vni all [json]", +DEFUN (show_evpn_nh_vni_all, + show_evpn_nh_vni_all_cmd, + "show evpn next-hops vni all [json]", SHOW_STR "EVPN\n" "Remote VTEPs\n" - "L3-VNI\n" + "L3 VNI\n" "All VNIs\n" JSON_STR) { @@ -3283,16 +3335,15 @@ void zebra_vty_init(void) /* Commands for VRF */ install_element(VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd); + install_element(VIEW_NODE, &show_evpn_global_cmd); install_element(VIEW_NODE, &show_evpn_vni_cmd); install_element(VIEW_NODE, &show_evpn_vni_vni_cmd); - install_element(VIEW_NODE, &show_evpn_l3vni_cmd); - install_element(VIEW_NODE, &show_evpn_l3vni_vni_cmd); - install_element(VIEW_NODE, &show_evpn_rmac_l3vni_mac_cmd); - install_element(VIEW_NODE, &show_evpn_rmac_l3vni_cmd); - install_element(VIEW_NODE, &show_evpn_rmac_l3vni_all_cmd); - install_element(VIEW_NODE, &show_evpn_nh_l3vni_ip_cmd); - install_element(VIEW_NODE, &show_evpn_nh_l3vni_cmd); - install_element(VIEW_NODE, &show_evpn_nh_l3vni_all_cmd); + install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd); + install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd); + install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd); + install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd); + install_element(VIEW_NODE, &show_evpn_nh_vni_cmd); + install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd); install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd); @@ -3303,7 +3354,8 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); - install_element(CONFIG_NODE, &no_vrf_vni_mapping_cmd); + install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd); + install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd); install_element(VRF_NODE, &vrf_vni_mapping_cmd); install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1690079f68..fb1aebecc3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -46,7 +46,6 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zebra_memory.h" #include "zebra/zebra_l2.h" -#include "lib/json.h" DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); @@ -59,6 +58,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); /* static function declarations */ +static int ip_prefix_send_to_client(vrf_id_t vrf_id, + struct prefix *p, + uint16_t cmd); static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, @@ -286,6 +288,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) : "Inactive"); } } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) { + if (!json) + vty_out(vty, " Default-gateway"); + else + json_object_boolean_true_add(json, "defaultGateway"); + } if (json == NULL) vty_out(vty, "\n"); } @@ -442,7 +450,8 @@ static void zl3vni_print_nh(zebra_neigh_t *n, ipaddr2str(&n->ip, buf2, sizeof(buf2))); vty_out(vty, " RMAC: %s\n", prefix_mac2str(&n->emac, buf1, sizeof(buf1))); - vty_out(vty, " Host-List:\n"); + vty_out(vty, " Refcount: %d\n", listcount(n->host_list)); + vty_out(vty, " Prefixes:\n"); for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p)) vty_out(vty, " %s\n", prefix2str(p, buf2, sizeof(buf2))); @@ -451,15 +460,16 @@ static void zl3vni_print_nh(zebra_neigh_t *n, json_object_string_add(json, "ip", ipaddr2str(&(n->ip), buf2, sizeof(buf2))); - json_object_string_add(json, "rmac", + json_object_string_add(json, "routerMac", prefix_mac2str(&n->emac, buf2, sizeof(buf2))); + json_object_int_add(json, "refCount", listcount(n->host_list)); for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p)) json_object_array_add(json_hosts, json_object_new_string( prefix2str(p, buf2, sizeof(buf2)))); - json_object_object_add(json, "hosts", json_hosts); + json_object_object_add(json, "prefixList", json_hosts); } } @@ -479,24 +489,27 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); vty_out(vty, " Remote VTEP: %s\n", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - vty_out(vty, " Host-List:\n"); + vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list)); + vty_out(vty, " Prefixes:\n"); for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p)) vty_out(vty, " %s\n", prefix2str(p, buf2, sizeof(buf2))); } else { json_hosts = json_object_new_array(); - json_object_string_add(json, "Rmac", + json_object_string_add(json, "routerMac", prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); - json_object_string_add(json, "vtep-ip", + json_object_string_add(json, "vtepIp", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); + json_object_int_add(json, "refCount", + listcount(zrmac->host_list)); for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p)) json_object_array_add(json_hosts, json_object_new_string( prefix2str(p, buf2, sizeof(buf2)))); - json_object_object_add(json, "hosts", json_hosts); + json_object_object_add(json, "prefixList", json_hosts); } } @@ -534,6 +547,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) vty_out(vty, " Auto Mac "); } + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) + vty_out(vty, " Sticky Mac "); + + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) + vty_out(vty, " Default-gateway Mac "); + vty_out(vty, "\n"); /* print all the associated neigh */ vty_out(vty, " Neighbors:\n"); @@ -739,17 +758,15 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet, return; if (!json_vni) { - vty_out(vty, "%-15s %-17s %6d\n", + vty_out(vty, "%-15s %-17s\n", ipaddr2str(&(n->ip), buf2, sizeof(buf2)), - prefix_mac2str(&n->emac, buf1, sizeof(buf1)), - listcount(n->host_list)); + prefix_mac2str(&n->emac, buf1, sizeof(buf1))); } else { - json_object_string_add(json_nh, "nexthop-ip", + json_object_string_add(json_nh, "nexthopIp", ipaddr2str(&n->ip, buf2, sizeof(buf2))); - json_object_string_add(json_nh, "rmac", + json_object_string_add(json_nh, "routerMac", prefix_mac2str(&n->emac, buf1, sizeof(buf1))); - json_object_int_add(json_nh, "refCnt", listcount(n->host_list)); json_object_object_add(json_vni, ipaddr2str(&(n->ip), buf2, sizeof(buf2)), json_nh); @@ -789,10 +806,9 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, if (json == NULL) { vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh); - vty_out(vty, "%-15s %-17s %6s\n", "IP", - "RMAC", "Refcnt"); + vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); } else - json_object_int_add(json_vni, "numNh", num_nh); + json_object_int_add(json_vni, "numNextHops", num_nh); memset(&wctx, 0, sizeof(struct nh_walk_ctx)); wctx.vty = vty; @@ -833,10 +849,9 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, } if (json == NULL) { - vty_out(vty, "\nVNI %u #MACs %u\n\n", + vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs); - vty_out(vty, "%-17s %-21s %-6s\n", "MAC", - "Remote VTEP", "Refcnt"); + vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP"); } else json_object_int_add(json_vni, "numRmacs", num_rmacs); @@ -872,18 +887,15 @@ static void zl3vni_print_rmac_hash(struct hash_backet *backet, return; if (!json) { - vty_out(vty, "%-17s %-21s %-6d\n", + vty_out(vty, "%-17s %-21s\n", prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), - inet_ntoa(zrmac->fwd_info.r_vtep_ip), - listcount(zrmac->host_list)); + inet_ntoa(zrmac->fwd_info.r_vtep_ip)); } else { - json_object_string_add(json_rmac, "rmac", + json_object_string_add(json_rmac, "routerMac", prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf))); - json_object_string_add(json_rmac, "vtep-ip", + json_object_string_add(json_rmac, "vtepIp", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - json_object_int_add(json_rmac, "refcnt", - listcount(zrmac->host_list)); json_object_object_add(json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), @@ -906,7 +918,10 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) if (!json) { vty_out(vty, "VNI: %u\n", zl3vni->vni); - vty_out(vty, " Local Vtep Ip: %s", + vty_out(vty, " Type: %s\n", "L3"); + vty_out(vty, " Tenant VRF: %s\n", + zl3vni_vrf_name(zl3vni)); + vty_out(vty, " Local Vtep Ip: %s\n", inet_ntoa(zl3vni->local_vtep_ip)); vty_out(vty, " Vxlan-Intf: %s\n", zl3vni_vxlan_if_name(zl3vni)); @@ -914,35 +929,34 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) zl3vni_svi_if_name(zl3vni)); vty_out(vty, " State: %s\n", zl3vni_state2str(zl3vni)); - vty_out(vty, " Vrf: %s\n", - zl3vni_vrf_name(zl3vni)); - vty_out(vty, " Rmac: %s\n", + vty_out(vty, " Router MAC: %s\n", zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); - vty_out(vty, " L2-VNIs: "); + vty_out(vty, " L2 VNIs: "); for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) vty_out(vty, "%u ", zvni->vni); vty_out(vty, "\n"); } else { json_vni_list = json_object_new_array(); json_object_int_add(json, "vni", zl3vni->vni); - json_object_string_add(json, "local-vtep-ip", + json_object_string_add(json, "type", "L3"); + json_object_string_add(json, "localVtepIp", inet_ntoa(zl3vni->local_vtep_ip)); - json_object_string_add(json, "vxlan-intf", + json_object_string_add(json, "vxlanIntf", zl3vni_vxlan_if_name(zl3vni)); - json_object_string_add(json, "svi-if", + json_object_string_add(json, "sviIntf", zl3vni_svi_if_name(zl3vni)); json_object_string_add(json, "state", zl3vni_state2str(zl3vni)); json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); - json_object_string_add(json, "rmac", + json_object_string_add(json, "routerMac", zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) { json_object_array_add(json_vni_list, json_object_new_int(zvni->vni)); } - json_object_object_add(json, "l2-vnis", json_vni_list); + json_object_object_add(json, "l2Vnis", json_vni_list); } } @@ -964,9 +978,11 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) if (json == NULL) { vty_out(vty, "VNI: %u\n", zvni->vni); - vty_out(vty, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id)); + vty_out(vty, " Type: %s\n", "L2"); + vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id)); } else { json_object_int_add(json, "vni", zvni->vni); + json_object_string_add(json, "type", "L2"); json_object_string_add(json, "vrf", vrf_id_to_name(zvni->vrf_id)); } @@ -978,11 +994,13 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) } num_macs = num_valid_macs(zvni); num_neigh = hashcount(zvni->neigh_table); - if (json == NULL) - vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n", - zvni->vxlan_if->name, zvni->vxlan_if->ifindex, + if (json == NULL) { + vty_out(vty, " VxLAN interface: %s\n", + zvni->vxlan_if->name); + vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex); + vty_out(vty," Local VTEP IP: %s\n", inet_ntoa(zvni->local_vtep_ip)); - else { + } else { json_object_string_add(json, "vxlanInterface", zvni->vxlan_if->name); json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); @@ -1033,7 +1051,6 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) { - char buf[ETHER_ADDR_STRLEN]; struct vty *vty = NULL; json_object *json = NULL; json_object *json_vni = NULL; @@ -1047,33 +1064,30 @@ static void zl3vni_print_hash(struct hash_backet *backet, return; if (!json) { - vty_out(vty, "%-10u %-15s %-20s %-20s %-5s %-37s %-18s\n", - zl3vni->vni, - inet_ntoa(zl3vni->local_vtep_ip), + vty_out(vty, + "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n", + zl3vni->vni, "L3", zl3vni_vxlan_if_name(zl3vni), - zl3vni_svi_if_name(zl3vni), - zl3vni_state2str(zl3vni), - zl3vni_vrf_name(zl3vni), - zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); + hashcount(zl3vni->rmac_table), + hashcount(zl3vni->nh_table), + "n/a", + zl3vni_vrf_name(zl3vni)); } else { char vni_str[VNI_STR_LEN]; snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); json_vni = json_object_new_object(); json_object_int_add(json_vni, "vni", zl3vni->vni); - json_object_string_add(json_vni, "local-ip", - inet_ntoa(zl3vni->local_vtep_ip)); - json_object_string_add(json_vni, "vxlan-if", + json_object_string_add(json_vni, "vxlanIf", zl3vni_vxlan_if_name(zl3vni)); - json_object_string_add(json_vni, "svi-if", - zl3vni_svi_if_name(zl3vni)); - json_object_string_add(json_vni, "state", - zl3vni_state2str(zl3vni)); - json_object_string_add(json_vni, "vrf", + json_object_int_add(json_vni, "numMacs", + hashcount(zl3vni->rmac_table)); + json_object_int_add(json_vni, "numArpNd", + hashcount(zl3vni->nh_table)); + json_object_string_add(json_vni, "numRemoteVteps", "n/a"); + json_object_string_add(json_vni, "type", "L3"); + json_object_string_add(json_vni, "tenantVrf", zl3vni_vrf_name(zl3vni)); - json_object_string_add(json_vni, "rmac", - zl3vni_rmac2str(zl3vni, buf, - sizeof(buf))); json_object_object_add(json, vni_str, json_vni); } @@ -1111,24 +1125,26 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) num_macs = num_valid_macs(zvni); num_neigh = hashcount(zvni->neigh_table); if (json == NULL) - vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u %-37s\n", - zvni->vni, + vty_out(vty, + "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n", + zvni->vni, "L2", zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", - inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, - num_vteps, + num_macs, num_neigh, num_vteps, vrf_id_to_name(zvni->vrf_id)); else { char vni_str[VNI_STR_LEN]; snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); json_vni = json_object_new_object(); + json_object_int_add(json_vni, "vni", zvni->vni); + json_object_string_add(json_vni, "type", "L2"); json_object_string_add(json_vni, "vxlanIf", zvni->vxlan_if ? zvni->vxlan_if->name : "unknown"); - json_object_string_add(json_vni, "vtepIp", - inet_ntoa(zvni->local_vtep_ip)); json_object_int_add(json_vni, "numMacs", num_macs); json_object_int_add(json_vni, "numArpNd", num_neigh); json_object_int_add(json_vni, "numRemoteVteps", num_vteps); + json_object_string_add(json_vni, "tenantVrf", + vrf_id_to_name(zvni->vrf_id)); if (num_vteps) { json_vtep_list = json_object_new_array(); for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { @@ -1409,7 +1425,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni, ZEBRA_NEIGH_SET_ACTIVE(n); zvni_neigh_send_add_to_client( - zvni->vni, &n->ip, &n->emac, 0); + zvni->vni, &n->ip, &n->emac, n->flags); } else { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( @@ -1519,8 +1535,14 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni, */ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char neigh_flags) { + u_char flags = 0; + + if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, ZEBRA_MACIP_ADD); } @@ -1692,7 +1714,37 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); } + return 0; +} + +static int zvni_advertise_subnet(zebra_vni_t *zvni, + struct interface *ifp, + int advertise) +{ + struct listnode *cnode = NULL, *cnnode = NULL; + struct connected *c = NULL; + struct ethaddr macaddr; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + + for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + struct prefix p; + + memcpy(&p, c->address, sizeof(struct prefix)); + + /* skip link local address */ + if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) + continue; + + apply_mask(&p); + if (advertise) + ip_prefix_send_to_client(ifp->vrf_id, &p, + ZEBRA_IP_PREFIX_ROUTE_ADD); + else + ip_prefix_send_to_client(ifp->vrf_id, &p, + ZEBRA_IP_PREFIX_ROUTE_DEL); + } return 0; } @@ -1729,6 +1781,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.vid = vxl->access_vlan; @@ -1748,9 +1801,14 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; + /* Only advertise in BGP if the knob is enabled */ + if (!advertise_gw_macip_enabled(zvni)) + return 0; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP", @@ -1759,7 +1817,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, ipaddr2str(ip, buf2, sizeof(buf2))); zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, - ZEBRA_MAC_TYPE_GW); + n->flags); return 0; } @@ -1793,16 +1851,21 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) return -1; - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP", - ifp->name, ifp->ifindex, zvni->vni, - prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2))); + /* only need to delete the entry from bgp if we sent it before */ + if (advertise_gw_macip_enabled(zvni)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + ifp->vrf_id, ifp->name, + ifp->ifindex, zvni->vni, + prefix_mac2str(&(n->emac), + NULL, + ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); - /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - ZEBRA_MAC_TYPE_GW); + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, + ZEBRA_MACIP_TYPE_GW); + } /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -1869,9 +1932,6 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, if (!zvni) return; - if (!advertise_gw_macip_enabled(zvni)) - return; - ifp = zvni->vxlan_if; if (!ifp) return; @@ -1985,7 +2045,6 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) { struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = backet->data; - u_char sticky = 0; if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || ((wctx->flags & DEL_REMOTE_MAC) @@ -1995,11 +2054,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 - : 0; zvni_mac_send_del_to_client( wctx->zvni->vni, &mac->macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + mac->flags); } if (wctx->uninstall) @@ -2074,8 +2131,16 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) * Inform BGP about local MAC addition. */ static int zvni_mac_send_add_to_client(vni_t vni, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char mac_flags) { + u_char flags = 0; + + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, ZEBRA_MACIP_ADD); } @@ -2084,8 +2149,16 @@ static int zvni_mac_send_add_to_client(vni_t vni, * Inform BGP about local MAC deletion. */ static int zvni_mac_send_del_to_client(vni_t vni, - struct ethaddr *macaddr, u_char flags) + struct ethaddr *macaddr, + u_char mac_flags) { + u_char flags = 0; + + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, ZEBRA_MACIP_DEL); } @@ -2393,15 +2466,13 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni, vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (vlan_if) { - if (advertise_gw_macip_enabled(zvni)) { - /* Add SVI MAC-IP */ - zvni_add_macip_for_intf(vlan_if, zvni); + /* Add SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); - /* Add VRR MAC-IP - if any*/ - vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); - if (vrr_if) - zvni_add_macip_for_intf(vrr_if, zvni); - } + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); neigh_read_for_vlan(zns, vlan_if); } @@ -2795,17 +2866,19 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) /* * Cleanup VNI/VTEP and update kernel */ -static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf) +static void zvni_cleanup_all(struct hash_backet *backet, void *arg) { zebra_vni_t *zvni = NULL; zebra_l3vni_t *zl3vni = NULL; + struct zebra_vrf *zvrf = (struct zebra_vrf *)arg; zvni = (zebra_vni_t *)backet->data; if (!zvni) return; /* remove from l3-vni list */ - zl3vni = zl3vni_from_vrf(zvni->vrf_id); + if (zvrf->l3vni) + zl3vni = zl3vni_lookup(zvrf->l3vni); if (zl3vni) listnode_delete(zl3vni->l2vnis, zvni); @@ -3158,13 +3231,13 @@ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) { - if (!is_l3vni_oper_up(zl3vni)) - return -1; - if (!(n->flags & ZEBRA_NEIGH_REMOTE) || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) return 0; + if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if)) + return 0; + return kernel_del_neigh(zl3vni->svi_if, &n->ip); } @@ -3712,6 +3785,63 @@ static void zl3vni_del_nh_hash_entry(struct hash_backet *backet, zl3vni_nh_del(zl3vni, n); } +static int ip_prefix_send_to_client(vrf_id_t vrf_id, + struct prefix *p, + uint16_t cmd) +{ + struct zserv *client = NULL; + struct stream *s = NULL; + char buf[PREFIX_STRLEN]; + + client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, cmd, vrf_id); + stream_put(s, p, sizeof(struct prefix)); + + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Send ip prefix %s %s on vrf %s", + prefix2str(p, buf, sizeof(buf)), + (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL", + vrf_id_to_name(vrf_id)); + + if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) + client->prefixadd_cnt++; + else + client->prefixdel_cnt++; + + return zebra_server_send_message(client); +} + +/* re-add remote rmac if needed */ +static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) +{ + char buf[ETHER_ADDR_STRLEN]; + zebra_mac_t *zrmac = NULL; + + zrmac = zl3vni_rmac_lookup(zl3vni, rmac); + if (!zrmac) + return 0; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Del remote RMAC %s L3VNI %u - readd", + prefix_mac2str(rmac, buf, sizeof(buf)), + zl3vni->vni); + + zl3vni_rmac_install(zl3vni, zrmac); + return 0; +} + /* Public functions */ /* handle evpn route in vrf table */ @@ -3834,8 +3964,7 @@ void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vty_out(vty, "Number of Remote RMACs known for this VNI: %u\n", num_rmacs); - vty_out(vty, "%-17s %-21s %-6s\n", "MAC", - "Remote VTEP", "Refcnt"); + vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP"); } else json_object_int_add(json, "numRmacs", num_rmacs); @@ -3966,10 +4095,9 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vty_out(vty, "Number of NH Neighbors known for this VNI: %u\n", num_nh); - vty_out(vty, "%-15s %-17s %6s\n", "IP", - "RMAC", "Refcnt"); + vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); } else - json_object_int_add(json, "numNh", num_nh); + json_object_int_add(json, "numNextHops", num_nh); hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); @@ -4053,52 +4181,40 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json) } } -/* - * Display L3 VNI hash table (VTY command handler). - */ -void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json) +void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, + json_object *json_vrfs) { - u_int32_t num_vnis; - void *args[2]; - json_object *json = NULL; - struct zebra_ns *zns = NULL; + char buf[ETHER_ADDR_STRLEN]; + zebra_l3vni_t *zl3vni = NULL; - if (!is_evpn_enabled()) { - if (use_json) - vty_out(vty, "{}\n"); + zl3vni = zl3vni_lookup(zvrf->l3vni); + if (!zl3vni) return; - } - zns = zebra_ns_lookup(NS_DEFAULT); - assert(zns); - - num_vnis = hashcount(zns->l3vni_table); - if (!num_vnis) { - if (use_json) - vty_out(vty, "{}\n"); - return; - } - - if (use_json) { - json = json_object_new_object(); - json_object_int_add(json, "numVnis", num_vnis); + if (!json_vrfs) { + vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n", + zvrf_name(zvrf), + zl3vni->vni, + zl3vni_vxlan_if_name(zl3vni), + zl3vni_svi_if_name(zl3vni), + zl3vni_state2str(zl3vni), + zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); } else { - vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis); - vty_out(vty, "%-10s %-15s %-20s %-20s %-5s %-37s %-18s\n", - "VNI", "Local-ip", "Vx-intf", "L3-SVI", "State", - "VRF", "Rmac"); - } - - args[0] = vty; - args[1] = json; - hash_iterate(zns->l3vni_table, - (void (*)(struct hash_backet *, void *))zl3vni_print_hash, - args); - - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + json_object *json_vrf = NULL; + json_vrf = json_object_new_object(); + json_object_string_add(json_vrf, "vrf", + zvrf_name(zvrf)); + json_object_int_add(json_vrf, "vni", zl3vni->vni); + json_object_string_add(json_vrf, "vxlanIntf", + zl3vni_vxlan_if_name(zl3vni)); + json_object_string_add(json_vrf, "sviIntf", + zl3vni_svi_if_name(zl3vni)); + json_object_string_add(json_vrf, "state", + zl3vni_state2str(zl3vni)); + json_object_string_add(json_vrf, "routerMac", + zl3vni_rmac2str(zl3vni, buf, + sizeof(buf))); + json_object_array_add(json_vrfs, json_vrf); } } @@ -4467,25 +4583,45 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, u_char use_json) { - zebra_vni_t *zvni; json_object *json = NULL; void *args[2]; if (!is_evpn_enabled()) return; - zvni = zvni_lookup(vni); - if (!zvni) { - if (use_json) - vty_out(vty, "{}\n"); - else - vty_out(vty, "%% VNI %u does not exist\n", vni); - return; - } + if (use_json) json = json_object_new_object(); args[0] = vty; args[1] = json; - zvni_print(zvni, (void *)args); + + if (is_vni_l3(vni)) { + zebra_l3vni_t *zl3vni = NULL; + + zl3vni = zl3vni_lookup(vni); + if (!zl3vni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + zl3vni_print(zl3vni, (void *)args); + } else { + zebra_vni_t *zvni; + + zvni = zvni_lookup(vni); + if (!zvni) { + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); + return; + } + + zvni_print(zvni, (void *)args); + } + if (use_json) { vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); @@ -4493,44 +4629,91 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, } } +/* Display all global details for EVPN */ +void zebra_vxlan_print_evpn(struct vty *vty, u_char uj) +{ + int num_l2vnis = 0; + int num_l3vnis = 0; + int num_vnis = 0; + json_object *json = NULL; + struct zebra_ns *zns = NULL; + struct zebra_vrf *zvrf = NULL; + + if (!is_evpn_enabled()) + return; + + zns = zebra_ns_lookup(NS_DEFAULT); + if (!zns) + return; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return; + + num_l3vnis = hashcount(zns->l3vni_table); + num_l2vnis = hashcount(zvrf->vni_table); + num_vnis = num_l2vnis + num_l3vnis; + + if (uj) { + json = json_object_new_object(); + json_object_string_add(json, "advertiseGatewayMacip", + zvrf->advertise_gw_macip ? "Yes" : "No"); + json_object_int_add(json, "numVnis", num_vnis); + json_object_int_add(json, "numL2Vnis", num_l2vnis); + json_object_int_add(json, "numL3Vnis", num_l3vnis); + } else { + vty_out(vty, "L2 VNIs: %u\n", num_l2vnis); + vty_out(vty, "L3 VNIs: %u\n", num_l3vnis); + vty_out(vty, "Advertise gateway mac-ip: %s\n", + zvrf->advertise_gw_macip ? "Yes" : "No"); + } + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + /* * Display VNI hash table (VTY command handler). */ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, u_char use_json) { - u_int32_t num_vnis; json_object *json = NULL; + struct zebra_ns *zns = NULL; void *args[2]; if (!is_evpn_enabled()) return; - num_vnis = hashcount(zvrf->vni_table); - if (!num_vnis) { - if (use_json) - vty_out(vty, "{}\n"); + + zns = zebra_ns_lookup(NS_DEFAULT); + if (!zns) return; - } - if (use_json) { + + + if (use_json) json = json_object_new_object(); - json_object_string_add(json, "advertiseGatewayMacip", - zvrf->advertise_gw_macip ? "Yes" : "No"); - json_object_int_add(json, "numVnis", num_vnis); - } else { - vty_out(vty, "Advertise gateway mac-ip: %s\n", - zvrf->advertise_gw_macip ? "Yes" : "No"); - vty_out(vty, "Number of VNIs: %u\n", num_vnis); - vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s %-37s\n", "VNI", - "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", - "# Remote VTEPs", "VRF"); - } + else + vty_out(vty, + "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n", + "VNI", "Type", "VxLAN IF", "# MACs", + "# ARPs", "# Remote VTEPs", "Tenant VRF"); + args[0] = vty; args[1] = json; + /* Display all L2-VNIs */ hash_iterate(zvrf->vni_table, (void (*)(struct hash_backet *, void *))zvni_print_hash, args); + /* Display all L3-VNIs */ + hash_iterate(zns->l3vni_table, + (void (*)(struct hash_backet *, void *))zl3vni_print_hash, + args); + if (use_json) { vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); @@ -4768,7 +4951,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, zvni->vni); ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0); + return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); } @@ -4879,6 +5062,17 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length, if (!mac && !n) continue; + /* Ignore the delete if this mac is a gateway mac-ip */ + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { + zlog_err("%u: Ignore Del for MAC %s neigh %s on VNI %u as it is configured as a default gateway", + zvrf_id(zvrf), + prefix_mac2str(&macaddr, buf, sizeof(buf)), + ipaddr2str(&ip, buf1, sizeof(buf1)), + vni); + continue; + } + /* Uninstall remote neighbor or MAC. */ if (n) { /* When the MAC changes for an IP, it is possible the @@ -4936,7 +5130,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, int update_mac = 0, update_neigh = 0; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; - u_char sticky; + u_char sticky = 0; + u_char flags = 0; struct interface *ifp = NULL; struct zebra_if *zif = NULL; @@ -4973,17 +5168,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); l += IPV4_MAX_BYTELEN; - /* Get 'sticky' flag. */ - STREAM_GETC(s, sticky); + /* Get flags - sticky mac and/or gateway mac */ + flags = stream_getc(s); + sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); l++; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s", - sticky ? "sticky " : "", + "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s", prefix_mac2str(&macaddr, buf, sizeof(buf)), ipaddr2str(&ip, buf1, sizeof(buf1)), vni, - inet_ntoa(vtep_ip), + inet_ntoa(vtep_ip), flags, zebra_route_string(client->proto)); /* Locate VNI hash entry - expected to exist. */ @@ -5025,13 +5220,26 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length, zvni_vtep_install(zvni, &vtep_ip); } - /* First, check if the remote MAC is unknown or has a change. If - * so, - * that needs to be updated first. Note that client could - * install - * MAC and MACIP separately or just install the latter. - */ mac = zvni_mac_lookup(zvni, &macaddr); + + /* Ignore the update if the mac is already present + as a gateway mac */ + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) && + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac", + zvrf_id(zvrf), + prefix_mac2str(&macaddr, + buf, sizeof(buf)), + ipaddr2str(&ip, buf1, + sizeof(buf1)), vni); + continue; + } + + /* check if the remote MAC is unknown or has a change. + * If so, that needs to be updated first. Note that client could + * install MAC and MACIP separately or just install the latter. + */ if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0) != sticky @@ -5146,7 +5354,6 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, zebra_vni_t *zvni; zebra_mac_t *mac; char buf[ETHER_ADDR_STRLEN]; - u_char sticky; zif = ifp->info; assert(zif); @@ -5178,9 +5385,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, ifp->name, ifp->ifindex, vni); /* Remove MAC from BGP. */ - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvni->vni, macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); /* * If there are no neigh associated with the mac delete the mac @@ -5205,11 +5410,12 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp, struct interface *br_if, struct ethaddr *macaddr, vlanid_t vid) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; vni_t vni; - zebra_vni_t *zvni; - zebra_mac_t *mac; + zebra_vni_t *zvni = NULL; + zebra_l3vni_t *zl3vni = NULL; + zebra_mac_t *mac = NULL; char buf[ETHER_ADDR_STRLEN]; zif = ifp->info; @@ -5221,6 +5427,11 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp, if (!is_evpn_enabled()) return 0; + /* check if this is a remote RMAC and readd simillar to remote macs */ + zl3vni = zl3vni_lookup(vni); + if (zl3vni) + return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr); + /* Locate hash entry; it is expected to exist. */ zvni = zvni_lookup(vni); if (!zvni) @@ -5253,7 +5464,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zebra_vni_t *zvni; zebra_mac_t *mac; char buf[ETHER_ADDR_STRLEN]; - u_char sticky; /* We are interested in MACs only on ports or (port, VLAN) that * map to a VNI. @@ -5282,9 +5492,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return 0; /* Remove MAC from BGP. */ - sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvni->vni, macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); @@ -5423,7 +5631,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (add) { zvni_process_neigh_on_local_mac_add(zvni, mac); return zvni_mac_send_add_to_client(zvni->vni, macaddr, - sticky); + mac->flags); } return 0; @@ -5687,10 +5895,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, } - /* check if we are advertising gw macip routes */ - if (!advertise_gw_macip_enabled(zvni)) - return 0; - memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); if (p->family == AF_INET) { @@ -6394,17 +6598,115 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, return 0; } -int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) +int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf) { zebra_l3vni_t *zl3vni = NULL; - zl3vni = zl3vni_from_vrf(zvrf_id(zvrf)); + if (zvrf->l3vni) + zl3vni = zl3vni_lookup(zvrf->l3vni); if (!zl3vni) return 0; + zl3vni->vrf_id = zvrf_id(zvrf); + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + return 0; +} + +int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf) +{ + zebra_l3vni_t *zl3vni = NULL; + + if (zvrf->l3vni) + zl3vni = zl3vni_lookup(zvrf->l3vni); + if (!zl3vni) + return 0; + + zl3vni->vrf_id = VRF_UNKNOWN; zebra_vxlan_process_l3vni_oper_down(zl3vni); + return 0; +} + +int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) +{ + zebra_l3vni_t *zl3vni = NULL; + vni_t vni; + + if (zvrf->l3vni) + zl3vni = zl3vni_lookup(zvrf->l3vni); + if (!zl3vni) + return 0; + + vni = zl3vni->vni; zl3vni_del(zl3vni); - zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0); + zebra_vxlan_handle_vni_transition(zvrf, vni, 0); + + return 0; +} + +/* + * Handle message from client to enable/disable advertisement of g/w macip + * routes + */ +int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, + struct zebra_vrf *zvrf) +{ + struct stream *s; + int advertise; + vni_t vni = 0; + zebra_vni_t *zvni = NULL; + struct interface *ifp = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + + if (zvrf_id(zvrf) != VRF_DEFAULT) { + zlog_err("EVPN GW-MACIP Adv for non-default VRF %u", + zvrf_id(zvrf)); + return -1; + } + + s = client->ibuf; + advertise = stream_getc(s); + vni = stream_get3(s); + + zvni = zvni_lookup(vni); + if (!zvni) + return 0; + + if (zvni->advertise_subnet == advertise) + return 0; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "EVPN subnet Adv %s on VNI %d , currently %s", + advertise ? "enabled" : "disabled", vni, + zvni->advertise_subnet ? "enabled" : "disabled"); + + + zvni->advertise_subnet = advertise; + + ifp = zvni->vxlan_if; + if (!ifp) + return 0; + + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return 0; + + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return 0; + + if (zvni->advertise_subnet) + zvni_advertise_subnet(zvni, vlan_if, 1); + else + zvni_advertise_subnet(zvni, vlan_if, 0); return 0; } @@ -6590,6 +6892,14 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) "Zebra VRF VNI Table"); } +/* Cleanup VNI info, but don't free the table. */ +void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf) +{ + if (!zvrf) + return; + hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); +} + /* Close all VNI handling */ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) { diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index b7def6acf8..d9801a8b60 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -31,6 +31,7 @@ #include "vlan.h" #include "vxlan.h" +#include "lib/json.h" #include "zebra/zebra_vrf.h" /* Is EVPN enabled? */ @@ -53,8 +54,12 @@ is_evpn_enabled() extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id); extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf); +extern int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf); +extern int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf); +extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf); extern void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, struct ipaddr *ip, u_char uj); +extern void zebra_vxlan_print_evpn(struct vty *vty, u_char uj); extern void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, struct ethaddr *rmac, u_char use_json); @@ -99,9 +104,8 @@ extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni, u_char extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, u_char use_json); extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json); -extern void zebra_vxlan_print_l3vnis(struct vty *vty, - u_char use_json); - +extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, + json_object *json_vrfs); extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, int add); extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if); @@ -140,6 +144,8 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length, struct zebra_vrf *zvrf); extern int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length, + struct zebra_vrf *zvrf); extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, struct zebra_vrf *zvrf); @@ -151,6 +157,7 @@ extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, int err_str_sz, int add); extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf); extern void zebra_vxlan_close_tables(struct zebra_vrf *); +extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *); extern void zebra_vxlan_ns_init(struct zebra_ns *zns); extern void zebra_vxlan_ns_disable(struct zebra_ns *zns); extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index db828c337e..0eb880e848 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -83,6 +83,10 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf) { } +void zebra_vxlan_print_evpn(struct vty *vty, u_char uj) +{ +} + void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char) { } @@ -103,10 +107,6 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni) { } -void zebra_vxlan_print_l3vnis(struct vty *vty) -{ -} - int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) { return 0; @@ -207,3 +207,7 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) { } + +void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf) +{ +} diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index ef6f9b99cb..8d34b3e2f1 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -70,6 +70,9 @@ struct zebra_vni_t_ { /* Flag for advertising gw macip */ u_int8_t advertise_gw_macip; + /* Flag for advertising gw macip */ + u_int8_t advertise_subnet; + /* Corresponding VxLAN interface. */ struct interface *vxlan_if; @@ -233,6 +236,7 @@ struct zebra_mac_t_ { #define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ #define ZEBRA_MAC_STICKY 0x08 /* Static MAC */ #define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */ +#define ZEBRA_MAC_DEF_GW 0x20 /* Local or remote info. */ union { @@ -314,6 +318,7 @@ struct zebra_neigh_t_ { #define ZEBRA_NEIGH_LOCAL 0x01 #define ZEBRA_NEIGH_REMOTE 0x02 #define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */ +#define ZEBRA_NEIGH_DEF_GW 0x08 enum zebra_neigh_state state; diff --git a/zebra/zserv.c b/zebra/zserv.c index 3ee2bb59ec..71437bab15 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2603,6 +2603,9 @@ static inline void zserv_handle_commands(struct zserv *client, case ZEBRA_ADVERTISE_DEFAULT_GW: zebra_vxlan_advertise_gw_macip(client, length, zvrf); break; + case ZEBRA_ADVERTISE_SUBNET: + zebra_vxlan_advertise_subnet(client, length, zvrf); + break; case ZEBRA_ADVERTISE_ALL_VNI: zebra_vxlan_advertise_all_vni(client, length, zvrf); break; diff --git a/zebra/zserv.h b/zebra/zserv.h index 4b3b0041b8..7d5f6b4543 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -114,6 +114,8 @@ struct zserv { u_int32_t l3vnidel_cnt; u_int32_t macipadd_cnt; u_int32_t macipdel_cnt; + u_int32_t prefixadd_cnt; + u_int32_t prefixdel_cnt; time_t connect_time; time_t last_read_time;