From ead40654de7260c0b66061a41da1aac0c4febef7 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 13 Nov 2017 03:19:52 -0800 Subject: [PATCH 01/29] bgpd/zebra/lib: Add Default Gateway extended community 1. Added default gw extended community 2. code modification to handle sticky-mac/default-gw-mac as they go together 3. show command support for newly added extended community 4. State in zebra to reflect if a mac/neigh is default gateway 5. show command enhancement to refelect the same in zebra commands Ticket: CM-17428 Review: CCR-6580 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_attr.c | 3 + bgpd/bgp_attr.h | 3 + bgpd/bgp_attr_evpn.c | 30 +++++++ bgpd/bgp_attr_evpn.h | 1 + bgpd/bgp_ecommunity.c | 3 + bgpd/bgp_evpn.c | 103 +++++++++++++++++++---- bgpd/bgp_evpn_private.h | 7 ++ lib/zclient.h | 4 +- zebra/zebra_vxlan.c | 162 ++++++++++++++++++++++++------------ zebra/zebra_vxlan_private.h | 2 + 10 files changed, 247 insertions(+), 71 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 206d91bfe9..f197ad16a3 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); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1de1bee0f9..ebe14a7ceb 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; 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_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 12cc425bd3..3e74e48793 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -506,7 +506,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; @@ -541,18 +541,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))); @@ -662,9 +662,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; @@ -719,6 +721,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); } @@ -776,13 +787,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); @@ -853,6 +864,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, @@ -870,11 +882,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; @@ -899,9 +916,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, @@ -931,6 +953,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 @@ -1129,7 +1173,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. */ @@ -1206,7 +1250,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, 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.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)); @@ -1394,22 +1439,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; @@ -1419,6 +1469,11 @@ 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); attr_ip6.nexthop = vpn->originator_ip; @@ -1430,12 +1485,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. @@ -1454,6 +1516,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); @@ -1462,6 +1528,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, @@ -1496,7 +1566,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; } @@ -4042,12 +4116,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" : "", 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_private.h b/bgpd/bgp_evpn_private.h index 2d52e1995d..f5a0998f62 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -257,6 +257,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/lib/zclient.h b/lib/zclient.h index c24f2b2a4e..892e0ea994 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -343,8 +343,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/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1690079f68..1d70e970ec 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -286,6 +286,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"); } @@ -534,6 +540,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"); @@ -1409,7 +1421,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 +1531,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); } @@ -1729,6 +1747,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 +1767,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 +1783,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 +1817,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 +1898,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 +2011,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 +2020,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 +2097,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 +2115,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 +2432,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); } @@ -4768,7 +4805,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 +4916,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 +4984,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 +5022,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 +5074,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 +5208,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 +5239,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 @@ -5253,7 +5312,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 +5340,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 +5479,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 +5743,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) { diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index ef6f9b99cb..ecbdbfd835 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -233,6 +233,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 +315,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; From e8d26197fa0203909c5b02b5556ff23e130795ac Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Sat, 18 Nov 2017 00:50:46 -0800 Subject: [PATCH 02/29] bgpd: vrf/vni mapping command for default instance Ticket: CM-18906 Review: CCR-6946 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vty.c | 56 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 92e1076b2e..3b731a64dd 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2275,10 +2275,59 @@ DEFUN (show_vrf, 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, 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, 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; @@ -2303,7 +2352,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; @@ -3286,7 +3335,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); From 31947174453c582e5804b9131ee04710e3700a71 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 20 Nov 2017 16:47:55 -0800 Subject: [PATCH 03/29] bgpd: unblock l2vpn evpn for non default vrf Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_vty.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c98cf9c327..3ef5e993fc 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6104,7 +6104,8 @@ DEFUN_NOSH (address_family_ipv4_safi, 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"); + 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); @@ -6126,7 +6127,8 @@ DEFUN_NOSH (address_family_ipv6_safi, 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"); + 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); @@ -6168,10 +6170,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; } From a6ad0a4183be908b594e70a60a66b67d74b8c946 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 20 Nov 2017 18:54:02 -0800 Subject: [PATCH 04/29] bgpd: bgpd crash in update all type2 routes Ticket: CM-18924 Review: Trivial Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 3e74e48793..46a983a880 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1476,6 +1476,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) 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; From b57ba6d2a893e196fbc96e5ab8ca17d0f8ddf171 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Tue, 21 Nov 2017 02:42:05 -0800 Subject: [PATCH 05/29] bgpd: carry two MPLS labels in EVPN NLRIs When doing symmetric routing, EVPN type-2 (MACIP) routes need to be advertised with two labels (VNIs) the first being the L2 VNI (identifying the VLAN) and the second being the L3 VNI (identifying the VRF). The receive processing needs to handle one or two labels too. Ticket: CM-18489 Review: CCR-6949 Testing: manual and bgp/evpn/mpls smoke Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 28 +++++---- bgpd/bgp_attr.h | 9 ++- bgpd/bgp_debug.c | 21 +++++-- bgpd/bgp_debug.h | 3 +- bgpd/bgp_evpn.c | 119 +++++++++++++++++++++++++----------- bgpd/bgp_evpn.h | 27 +++++++- bgpd/bgp_evpn_private.h | 20 ------ bgpd/bgp_label.c | 6 +- bgpd/bgp_mplsvpn.c | 4 +- bgpd/bgp_route.c | 116 ++++++++++++++++++++++------------- bgpd/bgp_route.h | 17 +++--- bgpd/bgp_routemap.c | 2 +- bgpd/bgp_updgrp_packet.c | 31 ++++++---- bgpd/bgp_zebra.c | 5 +- bgpd/rfapi/vnc_export_bgp.c | 2 +- 15 files changed, 261 insertions(+), 149 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f197ad16a3..3f3acbe0e2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2701,8 +2701,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id, struct attr *attr) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, + struct attr *attr) { if (safi == SAFI_MPLS_VPN) { if (addpath_encode) @@ -2714,8 +2715,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, stream_put(s, &p->u.prefix, PSIZE(p->prefixlen)); } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) { /* EVPN prefix - contents depend on type */ - bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode, - addpath_tx_id); + bgp_evpn_encode_prefix(s, p, prd, label, num_labels, + attr, addpath_encode, addpath_tx_id); } else if (safi == SAFI_LABELED_UNICAST) { /* Prefix write with label. */ stream_put_labeled_prefix(s, p, label); @@ -2843,8 +2844,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id) { size_t cp; size_t aspath_sizep; @@ -2866,7 +2867,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, + label, num_labels, addpath_encode, addpath_tx_id, attr); bgp_packet_mpattr_end(s, mpattrlen_pos); } @@ -3298,15 +3300,19 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, - u_int32_t addpath_tx_id, struct attr *attr) + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, + struct attr *attr) { u_char wlabel[3] = {0x80, 0x00, 0x00}; - if (safi == SAFI_LABELED_UNICAST) + if (safi == SAFI_LABELED_UNICAST) { label = (mpls_label_t *)wlabel; + num_labels = 1; + } - return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, + label, num_labels, addpath_encode, addpath_tx_id, attr); } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index ebe14a7ceb..1b1471a198 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -260,7 +260,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct bpacket_attr_vec_arr *vecarr, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, - mpls_label_t *, int, u_int32_t); + mpls_label_t *, u_int32_t, + int, u_int32_t); extern void bgp_dump_routes_attr(struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp(const void *, const void *); @@ -308,7 +309,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, struct attr *attr); extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, int addpath_encode, + mpls_label_t *label, u_int32_t num_labels, + int addpath_encode, u_int32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p); @@ -318,7 +320,8 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi, safi_t safi, - struct prefix_rd *prd, mpls_label_t *, + struct prefix_rd *prd, + mpls_label_t *, u_int32_t, int, u_int32_t, struct attr *); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 45ac8e6859..b08522b68b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2017,8 +2017,9 @@ int bgp_debug_zebra(struct prefix *p) const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, struct prefix_rd *prd, union prefixconstptr pu, - mpls_label_t *label, int addpath_valid, - u_int32_t addpath_id, char *str, int size) + mpls_label_t *label, u_int32_t num_labels, + int addpath_valid, u_int32_t addpath_id, + char *str, int size) { char rd_buf[RD_ADDRSTRLEN]; char pfx_buf[PREFIX_STRLEN]; @@ -2041,11 +2042,19 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, addpath_id); tag_buf[0] = '\0'; - if (bgp_labeled_safi(safi) && label) { - u_int32_t label_value; + if (bgp_labeled_safi(safi) && num_labels) { - label_value = decode_label(label); - sprintf(tag_buf, " label %u", label_value); + if (safi == SAFI_EVPN) { + char tag_buf2[20]; + + bgp_evpn_label2str(label, num_labels, tag_buf2, 20); + sprintf(tag_buf, " label %s", tag_buf2); + } else { + u_int32_t label_value; + + label_value = decode_label(label); + sprintf(tag_buf, " label %u", label_value); + } } if (prd) diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 5fe19b162b..7c773cfafb 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -153,7 +153,8 @@ extern int bgp_debug_zebra(struct prefix *p); extern int bgp_debug_count(void); extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *, - union prefixconstptr, mpls_label_t *, + union prefixconstptr, + mpls_label_t *, u_int32_t, int, u_int32_t, char *, int); const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data, size_t datalen); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 46a983a880..b20076d471 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1034,10 +1034,11 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def, bgp_def->peer_self, attr_new, rn); SET_FLAG(ri->flags, BGP_INFO_VALID); - /* L3-VNI goes in the label2 field */ + /* Type-5 routes advertise the L3-VNI */ bgp_info_extra_get(ri); vni2label(bgp_vrf->l3vni, &label); - memcpy(&ri->extra->label2, &label, BGP_LABEL_BYTES); + memcpy(&ri->extra->label, &label, sizeof(label)); + ri->extra->num_labels = 1; /* add the route entry to route node*/ bgp_info_add(rn, ri); @@ -1127,11 +1128,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_info *tmp_ri; struct bgp_info *local_ri, *remote_ri; struct attr *attr_new; - mpls_label_t label = MPLS_INVALID_LABEL; + mpls_label_t label[BGP_MAX_LABELS]; + u_int32_t num_labels = 1; int route_change = 1; u_char sticky = 0; + struct prefix_evpn *evp; *ri = NULL; + evp = (struct prefix_evpn *)&rn->p; + memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. Also, * identify if already known from remote, and if so, the one with the @@ -1196,9 +1201,20 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bgp_info_extra_get(tmp_ri); /* The VNI goes into the 'label' field of the route */ - vni2label(vpn->vni, &label); + vni2label(vpn->vni, &label[0]); + /* Type-2 routes may carry a second VNI - the L3-VNI */ + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + vni_t l3vni; - memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES); + l3vni = bgpevpn_get_l3vni(vpn); + if (l3vni) { + vni2label(l3vni, &label[1]); + num_labels++; + } + } + + memcpy(&tmp_ri->extra->label, label, sizeof(label)); + tmp_ri->extra->num_labels = num_labels; bgp_info_add(rn, tmp_ri); } else { tmp_ri = local_ri; @@ -1814,9 +1830,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, SET_FLAG(ri->flags, BGP_INFO_VALID); bgp_info_extra_get(ri); ri->extra->parent = parent_ri; - if (parent_ri->extra) + if (parent_ri->extra) { memcpy(&ri->extra->label, &parent_ri->extra->label, - BGP_LABEL_BYTES); + sizeof(ri->extra->label)); + ri->extra->num_labels = parent_ri->extra->num_labels; + } bgp_info_add(rn, ri); } else { if (attrhash_cmp(ri->attr, parent_ri->attr) @@ -1880,9 +1898,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(ri->flags, BGP_INFO_VALID); bgp_info_extra_get(ri); ri->extra->parent = parent_ri; - if (parent_ri->extra) + if (parent_ri->extra) { memcpy(&ri->extra->label, &parent_ri->extra->label, - BGP_LABEL_BYTES); + sizeof(ri->extra->label)); + ri->extra->num_labels = parent_ri->extra->num_labels; + } bgp_info_add(rn, ri); } else { if (attrhash_cmp(ri->attr, parent_ri->attr) @@ -2772,7 +2792,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, struct prefix_evpn p; u_char ipaddr_len; u_char macaddr_len; - mpls_label_t *label_pnt; + mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */ + u_int32_t num_labels = 0; int ret; /* Type-2 route should be either 33, 37 or 49 bytes or an @@ -2840,19 +2861,28 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, } pfx += ipaddr_len; - /* Get the VNI (in MPLS label field). */ - /* Note: We ignore the second VNI, if any. */ - label_pnt = (mpls_label_t *)pfx; + /* Get the VNI(s). Stored as bytes here. */ + num_labels++; + memset(label, 0, sizeof(label)); + memcpy(&label[0], pfx, BGP_LABEL_BYTES); + pfx += 3; + psize -= (33 + ipaddr_len); + /* Do we have a second VNI? */ + if (psize) { + num_labels++; + memcpy(&label[1], pfx, BGP_LABEL_BYTES); + pfx += 3; + } /* Process the route. */ if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, 0, NULL); + &prd, &label[0], num_labels, 0, NULL); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, NULL); + &prd, &label[0], num_labels, NULL); return ret; } @@ -2908,11 +2938,11 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, NULL, 0, NULL); + &prd, NULL, 0, 0, NULL); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, NULL, NULL); + &prd, NULL, 0, NULL); return ret; } @@ -2928,7 +2958,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, struct bgp_route_evpn evpn; u_char ippfx_len; u_int32_t eth_tag; - mpls_label_t *label_pnt; + mpls_label_t label; /* holds the VNI as in the packet */ int ret; /* Type-5 route should be 34 or 58 bytes: @@ -2994,23 +3024,27 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, pfx += 16; } - label_pnt = (mpls_label_t *)pfx; + /* Get the VNI (in MPLS label field). Stored as bytes here. */ + memset(&label, 0, sizeof(label)); + memcpy(&label, pfx, BGP_LABEL_BYTES); + pfx += 3; /* Process the route. */ if (!withdraw) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, 0, &evpn); + &prd, &label, 1, 0, &evpn); else ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, label_pnt, &evpn); + &prd, &label, 1, &evpn); return ret; } static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, + struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct attr *attr) { int len; @@ -3055,7 +3089,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, stream_put(s, &temp, 16); } - if (label) + if (num_labels) stream_put(s, label, 3); else stream_put3(s, 0); @@ -3447,14 +3481,20 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) } /* - * Function to display "tag" in route as a VNI. + * TODO: Hardcoded for a maximum of 2 VNIs right now */ -char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len) +char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels, + char *buf, int len) { vni_t vni; + vni_t vni1, vni2; - vni = label2vni(label); - snprintf(buf, len, "%u", vni); + vni1 = label2vni(label); + if (num_labels == 2) { + vni2 = label2vni(label+1); + snprintf(buf, len, "%u/%u", vni1, vni2); + } else + snprintf(buf, len, "%u", vni1); return buf; } @@ -3577,12 +3617,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) * Encode EVPN prefix in Update (MP_REACH) */ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, + struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct attr *attr, int addpath_encode, u_int32_t addpath_tx_id) { struct prefix_evpn *evp = (struct prefix_evpn *)p; - int ipa_len = 0; + int len, ipa_len = 0; if (addpath_encode) stream_putl(s, addpath_tx_id); @@ -3596,18 +3637,24 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, ipa_len = IPV4_MAX_BYTELEN; else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) ipa_len = IPV6_MAX_BYTELEN; - stream_putc(s, 33 + ipa_len); // 1 VNI + /* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */ + len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3; + if (ipa_len && num_labels > 1) /* There are 2 VNIs */ + len += 3; + stream_putc(s, len); stream_put(s, prd->val, 8); /* RD */ stream_put(s, 0, 10); /* ESI */ stream_putl(s, 0); /* Ethernet Tag ID */ stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */ stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */ stream_putc(s, 8 * ipa_len); /* IP address Length */ - if (ipa_len) - stream_put(s, &evp->prefix.ip.ip.addr, - ipa_len); /* IP */ - stream_put(s, label, - BGP_LABEL_BYTES); /* VNI is contained in 'tag' */ + if (ipa_len) /* IP */ + stream_put(s, &evp->prefix.ip.ip.addr, ipa_len); + /* 1st label is the L2 VNI */ + stream_put(s, label, BGP_LABEL_BYTES); + /* Include 2nd label (L3 VNI) if advertising MAC+IP */ + if (ipa_len && num_labels > 1) + stream_put(s, label+1, BGP_LABEL_BYTES); break; case BGP_EVPN_IMET_ROUTE: @@ -3621,7 +3668,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, case BGP_EVPN_IP_PREFIX_ROUTE: /* TODO: AddPath support. */ - evpn_mpattr_encode_type5(s, p, prd, label, attr); + evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr); break; default: diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 9400916845..b3b61db141 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -34,6 +34,27 @@ static inline int is_evpn_enabled(void) return bgp ? bgp->advertise_all_vni : 0; } +static inline void vni2label(vni_t vni, mpls_label_t *label) +{ + u_char *tag = (u_char *)label; + + tag[0] = (vni >> 16) & 0xFF; + tag[1] = (vni >> 8) & 0xFF; + tag[2] = vni & 0xFF; +} + +static inline vni_t label2vni(mpls_label_t *label) +{ + u_char *tag = (u_char *)label; + vni_t vni; + + vni = ((u_int32_t)*tag++ << 16); + vni |= (u_int32_t)*tag++ << 8; + vni |= (u_int32_t)(*tag & 0xFF); + + return vni; +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn, afi_t afi, safi_t safi); @@ -46,11 +67,13 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); -extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len); +extern char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels, + char *buf, int len); extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len); extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json); extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, + struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct attr *attr, int addpath_encode, u_int32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f5a0998f62..6003e03f35 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -228,26 +228,6 @@ static inline int is_vni_param_configured(struct bgpevpn *vpn) || is_export_rt_configured(vpn)); } -static inline void vni2label(vni_t vni, mpls_label_t *label) -{ - u_char *tag = (u_char *)label; - tag[0] = (vni >> 16) & 0xFF; - tag[1] = (vni >> 8) & 0xFF; - tag[2] = vni & 0xFF; -} - -static inline vni_t label2vni(mpls_label_t *label) -{ - u_char *tag = (u_char *)label; - vni_t vni; - - vni = ((u_int32_t)*tag++ << 16); - vni |= (u_int32_t)*tag++ << 8; - vni |= (u_int32_t)(*tag & 0xFF); - - return vni; -} - static inline void encode_rmac_extcomm(struct ecommunity_val *eval, struct ethaddr *rmac) { diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 60250513b6..38b39075be 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -103,7 +103,7 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri, if (!rn || !ri || !to) return MPLS_INVALID_LABEL; - remote_label = ri->extra ? ri->extra->label : MPLS_INVALID_LABEL; + remote_label = ri->extra ? ri->extra->label[0] : MPLS_INVALID_LABEL; from = ri->peer; reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); @@ -325,11 +325,11 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, if (attr) { bgp_update(peer, &p, addpath_id, attr, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, 0, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1, 0, NULL); } else { bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1, NULL); } } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 472b9d200a..0e2594ba8a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -214,11 +214,11 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, if (attr) { bgp_update(peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, 0, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL); } else { bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); } } /* Packet length consistency check. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fdc7f22ae8..234bde418b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -147,7 +147,8 @@ static struct bgp_info_extra *bgp_info_extra_new(void) { struct bgp_info_extra *new; new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_info_extra)); - new->label = MPLS_INVALID_LABEL; + new->label[0] = MPLS_INVALID_LABEL; + new->num_labels = 0; return new; } @@ -770,9 +771,9 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new, /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - if ((new->extra &&bgp_is_valid_label(&new->extra->label)) + if ((new->extra && bgp_is_valid_label(&new->extra->label[0])) != (exist->extra - && bgp_is_valid_label(&exist->extra->label))) { + && bgp_is_valid_label(&exist->extra->label[0]))) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", @@ -2670,7 +2671,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, - int sub_type, struct prefix_rd *prd, mpls_label_t *label, + int sub_type, struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn) { int ret; @@ -2681,9 +2683,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; + struct bgp_info_extra *extra; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; - char label_buf[20]; int connected = 0; int do_loop_check = 1; int has_valid_label = 0; @@ -2698,10 +2700,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, bgp = peer->bgp; rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); - has_valid_label = bgp_is_valid_label(label); - - if (has_valid_label) - sprintf(label_buf, "label %u", label_pton(label)); + /* TODO: Check to see if we can get rid of "is_valid_label" */ + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + has_valid_label = (num_labels > 0) ? 1 : 0; + else + has_valid_label = bgp_is_valid_label(label); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -2821,7 +2824,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, && attrhash_cmp(ri->attr, attr_new) && (!has_valid_label || memcmp(&(bgp_info_extra_get(ri))->label, label, - BGP_LABEL_BYTES) + num_labels * sizeof(mpls_label_t)) == 0) && (overlay_index_equal( afi, ri, evpn == NULL ? NULL : &evpn->eth_s_id, @@ -2832,7 +2835,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, @@ -2857,7 +2861,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, } bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -2883,7 +2888,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -2896,7 +2902,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, pfx_buf); @@ -2987,9 +2994,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { - memcpy(&(bgp_info_extra_get(ri))->label, label, - BGP_LABEL_BYTES); - bgp_set_valid_label(&(bgp_info_extra_get(ri))->label); + extra = bgp_info_extra_get(ri); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) + bgp_set_valid_label(&extra->label[0]); } #if ENABLE_BGP_VNC @@ -3126,7 +3136,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd %s", peer->host, pfx_buf); @@ -3137,9 +3148,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { - memcpy(&(bgp_info_extra_get(new))->label, label, - BGP_LABEL_BYTES); - bgp_set_valid_label(&(bgp_info_extra_get(new))->label); + extra = bgp_info_extra_get(new); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); + extra->num_labels = num_labels; + if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) + bgp_set_valid_label(&extra->label[0]); } /* Update Overlay Index */ @@ -3241,7 +3255,8 @@ filtered: peer->rcvd_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s", @@ -3276,7 +3291,8 @@ filtered: int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, - int sub_type, struct prefix_rd *prd, mpls_label_t *label, + int sub_type, struct prefix_rd *prd, + mpls_label_t *label, u_int32_t num_labels, struct bgp_route_evpn *evpn) { struct bgp *bgp; @@ -3312,7 +3328,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (!bgp_adj_in_unset(rn, peer, addpath_id)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( - afi, safi, prd, p, label, + afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug( @@ -3332,7 +3349,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host, @@ -3343,7 +3361,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw(rn, ri, peer, afi, safi, prd); else if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, + bgp_debug_rdpfxpath2str(afi, safi, prd, p, + label, num_labels, addpath_id ? 1 : 0, addpath_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("%s Can't find the route %s", peer->host, pfx_buf); @@ -3469,14 +3488,18 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, continue; struct bgp_info *ri = rn->info; - mpls_label_t label = (ri && ri->extra) - ? ri->extra->label - : MPLS_INVALID_LABEL; + u_int32_t num_labels = 0; + mpls_label_t *label_pnt = NULL; + + if (ri && ri->extra) + num_labels = ri->extra->num_labels; + if (num_labels) + label_pnt = &ri->extra->label[0]; ret = bgp_update(peer, &rn->p, ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, prd, &label, 1, - NULL); + BGP_ROUTE_NORMAL, prd, + label_pnt, num_labels, 1, NULL); if (ret < 0) { bgp_unlock_node(rn); @@ -4029,11 +4052,12 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, if (attr) ret = bgp_update(peer, &p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - NULL, NULL, 0, NULL); + NULL, NULL, 0, 0, NULL); else ret = bgp_withdraw(peer, &p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, NULL, NULL); + BGP_ROUTE_NORMAL, NULL, + NULL, 0, NULL); /* Address family configuration mismatch or maximum-prefix count overflow. */ @@ -4345,10 +4369,13 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, #if ENABLE_BGP_VNC mpls_label_t label = 0; #endif + u_int32_t num_labels = 0; union gw_addr add; assert(bgp_static); + if (bgp_static->label != MPLS_INVALID_LABEL) + num_labels = 1; rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, &bgp_static->prd); @@ -4466,7 +4493,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, attr_new, rn); SET_FLAG(new->flags, BGP_INFO_VALID); new->extra = bgp_info_extra_new(); - new->extra->label = bgp_static->label; + if (num_labels) { + new->extra->label[0] = bgp_static->label; + new->extra->num_labels = num_labels; + } #if ENABLE_BGP_VNC label = decode_label(&bgp_static->label); #endif @@ -6713,7 +6743,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, } } - label = decode_label(&binfo->extra->label); + label = decode_label(&binfo->extra->label[0]); if (bgp_is_valid_label(&label)) { if (json) { @@ -7051,14 +7081,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, #if defined(HAVE_CUMULUS) if (!json_paths && safi == SAFI_EVPN) { - char tag_buf[20]; + char tag_buf[30]; bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2)); vty_out(vty, " Route %s", buf2); tag_buf[0] = '\0'; - if (binfo->extra) { - bgp_evpn_label2str(&binfo->extra->label, tag_buf, - sizeof(tag_buf)); + if (binfo->extra && binfo->extra->num_labels) { + bgp_evpn_label2str(binfo->extra->label, + binfo->extra->num_labels, + tag_buf, sizeof(tag_buf)); vty_out(vty, " VNI %s", tag_buf); } vty_out(vty, "\n"); @@ -7692,13 +7723,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, /* Remote Label */ #if defined(HAVE_CUMULUS) - if (binfo->extra && bgp_is_valid_label(&binfo->extra->label) + if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]) && safi != SAFI_EVPN) #else - if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)) + if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])) #endif { - mpls_label_t label = label_pton(&binfo->extra->label); + mpls_label_t label = label_pton( + &binfo->extra->label[0]); if (json_paths) json_object_int_add(json_path, "remoteLabel", label); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index ae4759aad0..cd4d027c6e 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -59,6 +59,11 @@ enum bgp_show_type { #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n" #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" +/* Maximum number of labels we can process or send with a prefix. We + * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. + */ +#define BGP_MAX_LABELS 2 + /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. @@ -73,11 +78,9 @@ struct bgp_info_extra { /* Nexthop reachability check. */ u_int32_t igpmetric; - /* MPLS label - L2VNI */ - mpls_label_t label; - - /* MPLS label - L3-VNI */ - mpls_label_t label2; + /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ + mpls_label_t label[BGP_MAX_LABELS]; + u_int32_t num_labels; #if ENABLE_BGP_VNC union { @@ -360,10 +363,10 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *, /* this is primarily for MPLS-VPN */ extern int bgp_update(struct peer *, struct prefix *, u_int32_t, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, - mpls_label_t *, int, struct bgp_route_evpn *); + mpls_label_t *, u_int32_t, int, struct bgp_route_evpn *); extern int bgp_withdraw(struct peer *, struct prefix *, u_int32_t, struct attr *, afi_t, safi_t, int, int, - struct prefix_rd *, mpls_label_t *, + struct prefix_rd *, mpls_label_t *, u_int32_t, struct bgp_route_evpn *); /* for bgp_nexthop and bgp_damp */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 8c9f9f65ca..de2410e009 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -659,7 +659,7 @@ static route_map_result_t route_match_vni(void *rule, struct prefix *prefix, vni = *((vni_t *)rule); bgp_info = (struct bgp_info *)object; - if (vni == label2vni(&bgp_info->extra->label)) + if (vni == label2vni(&bgp_info->extra->label[0])) return RMAP_MATCH; } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index b63dfbed0a..9fa733a720 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -701,7 +701,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) int addpath_overhead = 0; u_int32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; - mpls_label_t label = MPLS_INVALID_LABEL; + mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL; + u_int32_t num_labels = 0; if (!subgrp) return NULL; @@ -772,7 +773,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) * attr. */ total_attr_len = bgp_packet_attribute( NULL, peer, s, adv->baa->attr, &vecarr, NULL, - afi, safi, from, NULL, NULL, 0, 0); + afi, safi, from, NULL, NULL, 0, 0, 0); space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) @@ -815,11 +816,15 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) if (rn->prn) prd = (struct prefix_rd *)&rn->prn->p; - if (safi == SAFI_LABELED_UNICAST) + if (safi == SAFI_LABELED_UNICAST) { label = bgp_adv_label(rn, binfo, peer, afi, safi); - else if (binfo && binfo->extra) - label = binfo->extra->label; + label_pnt = &label; + num_labels = 1; + } else if (binfo && binfo->extra) { + label_pnt = &binfo->extra->label[0]; + num_labels = binfo->extra->num_labels; + } if (stream_empty(snlri)) mpattrlen_pos = bgp_packet_mpattr_start( @@ -827,8 +832,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) adv->baa->attr); bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, - &label, addpath_encode, - addpath_tx_id, adv->baa->attr); + label_pnt, num_labels, + addpath_encode, addpath_tx_id, + adv->baa->attr); } num_pfx++; @@ -857,7 +863,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) send_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, &label, + bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, + label_pnt, num_labels, addpath_encode, addpath_tx_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", @@ -1009,7 +1016,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) } bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, - NULL, addpath_encode, + NULL, 0, addpath_encode, addpath_tx_id, NULL); } @@ -1018,7 +1025,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { char pfx_buf[BGP_PRD_PATH_STRLEN]; - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, + bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0, addpath_encode, addpath_tx_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 @@ -1132,7 +1139,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, stream_putw(s, 0); total_attr_len = bgp_packet_attribute( NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL, - addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); + 0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); /* Set Total Path Attribute Length. */ stream_putw_at(s, pos, total_attr_len); @@ -1227,7 +1234,7 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp) mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); bgp_packet_mpunreach_prefix( - s, &p, afi, safi, NULL, NULL, addpath_encode, + s, &p, afi, safi, NULL, NULL, 0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL); /* Set the mp_unreach attr's length */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index de170fdd01..2a35645ee8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1142,10 +1142,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; } - if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label) + if (mpinfo->extra && + bgp_is_valid_label(&mpinfo->extra->label[0]) && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { has_valid_label = 1; - label = label_pton(&mpinfo->extra->label); + label = label_pton(&mpinfo->extra->label[0]); api_nh->label_num = 1; api_nh->labels[0] = label; diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index d4921ce40a..a37e705612 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -317,7 +317,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn, iattr, /* bgp_update copies this attr */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, /* tag not used for unicast */ + NULL, 0, /* tag not used for unicast */ 0, NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); } From 31310b25f20260b66ab7a4ce726f57d815424867 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Sun, 19 Nov 2017 21:47:04 -0800 Subject: [PATCH 06/29] bgpd: advertise VNI subnet In EVPN symmetric routing, not all subnets are presents everywhere. We have multiple scenarios where a host might not get learned locally. 1. GARP miss 2. SVI down/up 3. Silent host We need a mechanism to resolve such hosts. In order to achieve this, we will be advertising a subnet route from a box and that box will help in resolving the ARP to such hosts. Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 27 +++---- bgpd/bgp_evpn.h | 4 +- bgpd/bgp_evpn_private.h | 3 + bgpd/bgp_evpn_vty.c | 82 +++++++++++++++++++++ bgpd/bgp_route.c | 4 +- bgpd/bgp_zebra.c | 72 +++++++++++++++++++ bgpd/bgp_zebra.h | 3 +- lib/log.c | 3 + lib/zclient.c | 10 +++ lib/zclient.h | 5 ++ zebra/zebra_vxlan.c | 137 ++++++++++++++++++++++++++++++++++++ zebra/zebra_vxlan.h | 2 + zebra/zebra_vxlan_private.h | 3 + zebra/zserv.c | 3 + zebra/zserv.h | 2 + 15 files changed, 342 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index b20076d471..1a9b26764c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -3188,20 +3188,20 @@ 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); + 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)); } } @@ -3218,12 +3218,12 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, 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, +void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, afi_t afi, safi_t safi) { int ret = 0; @@ -3233,20 +3233,17 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn, 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); + build_type5_prefix_from_ip_prefix(&evp, p); ret = update_evpn_type5_route(bgp_vrf, &evp); if (ret) { zlog_err( "%u failed to create 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)); } } @@ -3259,8 +3256,12 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, struct bgp_node *rn = NULL; 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)) { + + if (!rn->info) + continue; + bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, afi, safi); + } } void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index b3b61db141..cff9d65468 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -56,10 +56,10 @@ static inline vni_t label2vni(mpls_label_t *label) } extern void bgp_evpn_advertise_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_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); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 6003e03f35..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; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index b463896c49..932046f7e0 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2271,6 +2271,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 +2356,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 +2469,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, @@ -4118,5 +4197,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_route.c b/bgpd/bgp_route.c index 234bde418b..7ee84c3531 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2226,9 +2226,9 @@ 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, 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. */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2a35645ee8..970b3eefbf 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1635,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; @@ -1821,6 +1844,53 @@ 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, + AFI_IP, + SAFI_UNICAST); + else + return bgp_evpn_advertise_type5_route(bgp_vrf, &p, + 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) @@ -1853,6 +1923,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/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/zclient.c b/lib/zclient.c index a4bd2bda32..a4fa0966a7 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2234,6 +2234,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 892e0ea994..8554f3e39d 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); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1d70e970ec..6b92d80953 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -59,6 +59,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, @@ -1710,7 +1713,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; } @@ -3749,6 +3782,43 @@ 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); + /* BGP may not be running. */ + if (!client) + return 0; + + s = client->obuf; + stream_reset(s); + + zserv_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); +} + /* Public functions */ /* handle evpn route in vrf table */ @@ -6461,6 +6531,73 @@ int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) 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; +} + /* * Handle message from client to enable/disable advertisement of g/w macip * routes diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index b7def6acf8..4e1eedd0dc 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -140,6 +140,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); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index ecbdbfd835..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; 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; From 4cce389e0ee6e661f5761dbb9baabb941eceee14 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 15 Nov 2017 01:01:00 -0800 Subject: [PATCH 07/29] bgpd/zebra: show command enhancements for EVPN symmetric routing 0. move all global EVPN details to 'show evpn [json]' command 1. change "VRF" to "Tenant VRF" in 'show evpn vni' 2. change 'show vrf vni' command to tabular form and add l3-vni related params to the output 3. show evpn rmac should show refcount only in detailed output 4. show evpn next-hop should show refcount only in detailed output 5. move VRF in 'show evpn l3vni' to the end 6. add num rmacs and num nexthops to show evpn l3vni 7. remove "info" from 'show bgp vrf <> l3vni info' 8. show evpn vni should show l2vni details or l3 vni details 9. show evpn vni should show both L2 and L3 VNIs 10. show bgp l2vpn evpn - shows all global bgp l2vpn evpn details 11. show bgp l2vpn evpn vni - will show both l2 and l3 vnis 12. show bgp l2vpn evpn vni - should show both l2 and l3 vnis 13. follow camel notation for all json keys Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn_vty.c | 267 +++++++++++++++++++++++++++---- zebra/zebra_vty.c | 130 ++++++--------- zebra/zebra_vxlan.c | 333 ++++++++++++++++++++++----------------- zebra/zebra_vxlan.h | 7 +- zebra/zebra_vxlan_null.c | 8 +- 5 files changed, 487 insertions(+), 258 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 932046f7e0..7d4a199f02 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -335,6 +335,83 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, 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 +425,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 +441,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 +649,108 @@ 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, "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,6 +781,7 @@ 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", @@ -608,8 +790,8 @@ static void show_vni_entry(struct hash_backet *backet, void *args[]) 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)); } @@ -2181,10 +2363,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 +2390,6 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni, return; } } - - display_vni(vty, vpn, json); } /* @@ -2202,28 +2398,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); + } /* @@ -2642,16 +2839,20 @@ 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; + 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)) @@ -2661,26 +2862,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); + if (!num_l2vnis) + return CMD_SUCCESS; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) { + if (bgp_temp->l3vni) + 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, "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; @@ -2689,7 +2900,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) { @@ -2767,7 +2978,6 @@ DEFUN(show_bgp_l2vpn_evpn_route, json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } - return CMD_SUCCESS; } @@ -3623,13 +3833,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]; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 3b731a64dd..fc4e37f0f9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2393,29 +2393,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) { @@ -2428,6 +2415,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]", @@ -2463,44 +2463,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" @@ -2519,13 +2488,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) { @@ -2538,13 +2507,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) { @@ -2555,13 +2524,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" @@ -2582,13 +2551,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) { @@ -2601,13 +2570,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) { @@ -3315,16 +3284,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); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 6b92d80953..47aa883d11 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"); @@ -451,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))); @@ -460,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); } } @@ -488,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); } } @@ -754,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); @@ -804,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; @@ -848,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); @@ -887,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)), @@ -921,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)); @@ -929,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); } } @@ -979,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)); } @@ -993,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); @@ -1048,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; @@ -1062,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); } @@ -1126,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) { @@ -3941,8 +3942,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); @@ -4073,10 +4073,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); @@ -4160,52 +4159,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); } } @@ -4574,25 +4561,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)); @@ -4600,44 +4607,88 @@ 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; + 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); + + if (uj) { + json = json_object_new_object(); + json_object_string_add(json, "advertiseGatewayMacip", + zvrf->advertise_gw_macip ? "Yes" : "No"); + 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)); diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 4e1eedd0dc..2a50591100 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? */ @@ -55,6 +56,7 @@ extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id); 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 +101,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); diff --git a/zebra/zebra_vxlan_null.c b/zebra/zebra_vxlan_null.c index db828c337e..fa6ed77e53 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; From a56547355d50092353de9662d77b4f9af9f7843b Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Tue, 28 Nov 2017 15:43:42 -0800 Subject: [PATCH 08/29] zebra: write vni to config in default vrf Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vrf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 95426683a8..000beba870 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -476,7 +476,13 @@ 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 (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); From a9a76262298daae4ac094480df87d3c5e1fdb256 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 29 Nov 2017 02:25:35 -0800 Subject: [PATCH 09/29] zebra: re-add remote RMAC if needed Kernel can delete a frr installed remote RMAC on a L3-VNI. We should re-add if such a siatuation occurs as we are the owner of the RMAC. This behavor is same for remote MACs as well and was missing for RMACs. Ticket: CM-18762 Review: CCR-6992 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 47aa883d11..3812a64f16 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3820,6 +3820,26 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, 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 */ @@ -5385,11 +5405,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; @@ -5401,6 +5422,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) From a58e6e0c27a1798200ea0b8bb13f52edb5824a71 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 29 Nov 2017 16:24:07 -0800 Subject: [PATCH 10/29] zebra: Do not check for l3vni oper up in nh uninstall We shouldnt check for l3vni oper up while uninstalling the next-hop. Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 3812a64f16..7b79c5be4d 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3229,9 +3229,6 @@ 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; From fb8384733f1865dbec3a8def0fb18ab4d78f0b47 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 29 Nov 2017 17:50:42 -0800 Subject: [PATCH 11/29] bgpd: fix show bgp l2vpn evpn vni command We bail in the command if no l2vnis are present. This is incorrect as we now print both l2 and l3 vnis together. Ticket: CM-19022 Review: Trivial Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn_vty.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 7d4a199f02..607a058184 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2864,8 +2864,6 @@ DEFUN(show_bgp_l2vpn_evpn_vni, if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) { num_l2vnis = hashcount(bgp_def->vnihash); - if (!num_l2vnis) - return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) { if (bgp_temp->l3vni) From 84915b0a15e32a51622f28b6bcafff58a4b02d6d Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Dec 2017 17:36:37 -0800 Subject: [PATCH 12/29] *: Handle VRF configuration when VRF gets inactivated and activated A VRF is active only when the corresponding VRF device is present in the kernel. However, when the kernel VRF device is removed, the VRF container in FRR should go away only if there is no user configuration for it. Otherwise, when the VRF device is created again so that the VRF becomes active, FRR cannot take the correct actions. Example configuration for the VRF includes static routes and EVPN L3 VNI. Note that a VRF is currently considered to be "configured" as soon as the operator has issued the "vrf " command in FRR. Such a configured VRF is not deleted upon VRF device removal, it is only made inactive. A VRF that is "configured" can be deleted only upon operator action and only if the VRF has been deactivated i.e., the VRF device removed from the kernel. This is an existing restriction. To implement this change, the VRF disable and delete actions have been modified. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Mitesh Kanjariya Reviewed-by: Don Slice Ticket: CM-18553, CM-18918, CM-10139 Reviewed By: CCR-7022 Testing Done: 1. vrf and pim-vrf automation tests 2. Multiple VRF delete and readd (ifdown, ifup-with-depends) 3. FRR stop, start, restart 4. Networking restart 5. Configuration delete and readd Some of the above tests run in different sequences (manually). --- lib/vrf.c | 34 ++++++++++++++----- lib/vrf.h | 17 +++++++++- zebra/zebra_mpls.c | 10 ++++++ zebra/zebra_mpls.h | 7 ++++ zebra/zebra_ns.c | 9 +++-- zebra/zebra_vrf.c | 73 +++++++++++++++++++++++++++------------- zebra/zebra_vxlan.c | 51 +++++++++++++++++++++++++--- zebra/zebra_vxlan.h | 4 +++ zebra/zebra_vxlan_null.c | 4 +++ 9 files changed, 168 insertions(+), 41 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index 2fa3a9c0ef..bc081796c5 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 @@ -445,6 +456,9 @@ DEFUN_NOSH (vrf, vrfp = vrf_get(VRF_UNKNOWN, vrfname); + /* Mark as user configured. */ + SET_FLAG(vrfp->status, VRF_CONFIGURED); + VTY_PUSH_CONTEXT(VRF_NODE, vrfp); return CMD_SUCCESS; @@ -473,6 +487,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..89d2316354 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 is configured by user in frr */ /* Interfaces belonging to this VRF */ struct if_name_head ifaces_by_name; @@ -119,6 +120,20 @@ 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); +} + /* * Utilities to obtain the user data */ 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 22c771c348..900474a611 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -378,6 +378,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 000beba870..6c9171c95c 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -82,7 +82,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( @@ -106,9 +106,16 @@ static int zebra_vrf_enable(struct vrf *vrf) 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); + /* 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 +139,9 @@ static int zebra_vrf_enable(struct vrf *vrf) } } + /* Kick off any VxLAN-EVPN processing. */ + zebra_vxlan_vrf_enable(zvrf); + return 0; } @@ -142,13 +152,16 @@ static int zebra_vrf_disable(struct vrf *vrf) struct route_table *stable; struct route_node *rn; struct static_route *si; + u_int32_t table_id; afi_t afi; safi_t safi; - 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,23 +174,15 @@ static int zebra_vrf_disable(struct vrf *vrf) afi, safi, &rn->p, NULL, si); } - return 0; -} - -static int zebra_vrf_delete(struct vrf *vrf) -{ - struct zebra_vrf *zvrf = vrf->info; - struct route_table *table; - u_int32_t table_id; - afi_t afi; - safi_t safi; - unsigned i; - - assert(zvrf); + /* 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); - /* uninstall everything */ + /* uninstall all routes */ if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) { struct interface *ifp; @@ -197,16 +202,32 @@ static int zebra_vrf_delete(struct vrf *vrf) [table_id]); } - /* Cleanup Vxlan table and update kernel */ - zebra_vxlan_close_tables(zvrf); - - zebra_mpls_close_tables(zvrf); + /* Cleanup Vxlan, MPLS and PW tables. */ + zebra_vxlan_cleanup_tables(zvrf); + zebra_mpls_cleanup_tables(zvrf); zebra_pw_exit(zvrf); FOR_ALL_INTERFACES (vrf, ifp) if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); } + return 0; +} + +static int zebra_vrf_delete(struct vrf *vrf) +{ + struct zebra_vrf *zvrf = vrf->info; + struct route_table *table; + u_int32_t table_id; + afi_t afi; + safi_t safi; + unsigned i; + + assert(zvrf); + 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++) { struct listnode *lnode, *nnode; @@ -224,6 +245,10 @@ 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; @@ -251,7 +276,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); @@ -482,7 +507,7 @@ static int vrf_config_write(struct vty *vty) vty_out(vty, "!\n"); } - if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { + if (vrf_is_user_cfged(vrf)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7b79c5be4d..51b4f23151 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2866,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); @@ -6590,17 +6592,48 @@ 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; } @@ -6853,6 +6886,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 2a50591100..d9801a8b60 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -54,6 +54,9 @@ 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); @@ -154,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 fa6ed77e53..0eb880e848 100644 --- a/zebra/zebra_vxlan_null.c +++ b/zebra/zebra_vxlan_null.c @@ -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) +{ +} From d560078848fcfba9a57cb765a746f3f605a079c4 Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Dec 2017 22:29:47 -0800 Subject: [PATCH 13/29] Revert "zebra: Do not check for l3vni oper up in nh uninstall" This reverts commit d8f5884846ead8fc78f36c68db5ed52e758b6e87. --- zebra/zebra_vxlan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 51b4f23151..90b0516276 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3231,6 +3231,9 @@ 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; From fa409e1eeb74bcdf841c9c7ae16dfd2e854341bd Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Dec 2017 23:31:22 -0800 Subject: [PATCH 14/29] zebra: Fix check when uninstalling remote next hops Only check on L3-VNI SVI status when uninstalling remote next hops. Signed-off-by: Vivek Venkatraman Ticket: CM-19036 Reviewed By: None Testing Done: 1. Networking restart 2. VxLAN interface disable/enable 3. VRF delete and readd --- zebra/zebra_vxlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 90b0516276..69ed93a084 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3231,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); } From 47b7136955e81f2fc128d609cd09fd63669e6a9f Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Sat, 2 Dec 2017 16:27:29 -0800 Subject: [PATCH 15/29] bgpd: provide filter for ip prefix route in bgp l2vpn evpn route cmd Ticket: CM-19000 Review: ccr-7008 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn_vty.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 607a058184..85f8d89df9 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2932,7 +2932,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 @@ -2941,6 +2941,7 @@ DEFUN(show_bgp_l2vpn_evpn_route, "Specify Route type\n" "MAC-IP (Type-2) route\n" "Multicast (Type-3) route\n" + "Prefix route" JSON_STR) { struct bgp *bgp; @@ -2965,6 +2966,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; } From aa9db9e6e27beb00fb8bca643c3fdbfbdfdb125c Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Sat, 2 Dec 2017 16:53:59 -0800 Subject: [PATCH 16/29] bgpd: filter for prefix route in route rd commands Ticket: CM-19000 Review: crr-7008 Testing: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn_vty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 85f8d89df9..9f35671968 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2941,7 +2941,7 @@ DEFUN(show_bgp_l2vpn_evpn_route, "Specify Route type\n" "MAC-IP (Type-2) route\n" "Multicast (Type-3) route\n" - "Prefix route" + "Prefix route\n" JSON_STR) { struct bgp *bgp; @@ -2987,7 +2987,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 @@ -2998,6 +2998,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; @@ -3035,6 +3036,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; } From 2f69f6d36855cd7520b36d4bad1b63f146dd5cbe Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 4 Dec 2017 09:52:54 -0800 Subject: [PATCH 17/29] bgpd: Use source route's path attributes for type-5 routes When an IPv4 or IPv6 unicast route is injected into EVPN as a type-5 route (upon user configuration), ensure that the source route (best path)'s path attributes are used to build the EVPN type-5 route. This will result in correct AS_PATH and ORIGIN attributes for the type-5 route so that it doesn't appear that all type-5 routes are locally sourced. This is necessary to ensure that external paths (IPv4 or IPv6 from EBGP peer) are preferred over internal EVPN paths, if both exist. Signed-off-by: Vivek Venkatraman Ticket: CM-19051 Reviewed By: CCR-7009 Testing Done: Verify failed scenario --- bgpd/bgp_evpn.c | 56 ++++++++++++++++++++++++++++++++++-------------- bgpd/bgp_evpn.h | 1 + bgpd/bgp_route.c | 4 +++- bgpd/bgp_zebra.c | 2 ++ 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1a9b26764c..70500f39d4 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1070,7 +1070,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; @@ -1083,9 +1084,16 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, if (!bgp_def) return -1; - /* 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; @@ -3222,8 +3230,14 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, } -/* advertise ip prefix as type-5 route*/ +/* + * 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; @@ -3238,29 +3252,39 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, return; build_type5_prefix_from_ip_prefix(&evp, p); - ret = update_evpn_type5_route(bgp_vrf, &evp); - if (ret) { + 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(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; table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - - if (!rn->info) - continue; - bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, afi, safi); + /* 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; + } + } } } diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index cff9d65468..a8dcbc112b 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -57,6 +57,7 @@ static inline vni_t label2vni(mpls_label_t *label) extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, 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 prefix *p, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7ee84c3531..5ed1b42407 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2226,7 +2226,9 @@ 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->p, 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->p, afi, safi); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 970b3eefbf..8bd594995c 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1872,10 +1872,12 @@ static void bgp_zebra_process_local_ip_prefix(int cmd, 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); From 65c3a7c4e51e6c5e710687e73cfd675e4da5a480 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 4 Dec 2017 13:10:09 -0800 Subject: [PATCH 18/29] lib: Handle configured VRFs at termination When shutting down, ensure that all VRFs including "configured" ones are cleaned up properly. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Ticket: CM-19069 Reviewed By: CCR-7011 Testing Done: Manual verification of failed scenario --- lib/vrf.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index bc081796c5..23eaa042ec 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -419,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. */ From 1d72e48aff5e7a4ceefe8a9dbeee1868a9a6f8c0 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 4 Dec 2017 20:05:15 -0800 Subject: [PATCH 19/29] lib: Display configured VRFs Ensure that configured VRFs are displayed in the running configuration. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Mitesh Kanjariya Ticket: CM-10139 Reviewed By: CCR-7012 Testing Done: Verify failed test scenario --- vtysh/vtysh_config.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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; From d4454626490f9f0b8d1efec36feefdd3ad10dd45 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 7 Dec 2017 08:28:04 -0800 Subject: [PATCH 20/29] *: Reintroduce JSON keywords for EVPN Bring back "numVnis" and "originatorIp" for backwards compatibility. Signed-off-by: Vivek Venkatraman Ticket: CM-19119 Reviewed By: Trivial Testing Done: Manual, evpn_tests.py --- bgpd/bgp_evpn_vty.c | 7 +++++++ zebra/zebra_vxlan.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 9f35671968..56c138ae8c 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -679,6 +679,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, 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)); @@ -786,6 +788,8 @@ static void show_vni_entry(struct hash_backet *backet, void *args[]) 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))); @@ -2846,6 +2850,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni, 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; @@ -2869,6 +2874,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni, if (bgp_temp->l3vni) num_l3vnis++; } + num_vnis = num_l2vnis + num_l3vnis; if (uj) { json_object_string_add(json, "advertiseGatewayMacip", bgp_def->advertise_gw_macip @@ -2878,6 +2884,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni, 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 { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 69ed93a084..c05abc3528 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -4634,6 +4634,7 @@ 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; @@ -4651,11 +4652,13 @@ void zebra_vxlan_print_evpn(struct vty *vty, u_char uj) 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 { From 5ee65f6f3e6e6e9911753cd3c8d70a39b649bed4 Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 8 Dec 2017 16:36:27 -0800 Subject: [PATCH 21/29] bgpd: Fix attribute handling for type-5 routes When a EVPN type-5 route is formed by using the source IP route's AS-path, the AS-path is not locally generated and should not be "uninterned" (i.e., have its reference count incorrectly updated). An incorrect update of the reference count can lead to asserts or crashes at a later stage. Signed-off-by: Vivek Venkatraman Ticket: CM-19121 Reviewed By: CCR-7028 Testing Done: 1. Manual testing by Vivek and Anitha 2. No automation run since this area has no coverage yet --- bgpd/bgp_evpn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 70500f39d4..4e40daadb6 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1120,7 +1120,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; } From 9d97533e37d3614755ef94e75c41e70d0404218b Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 11 Dec 2017 14:38:15 -0800 Subject: [PATCH 22/29] zebra: Refine cleanup when a VRF with configuration gets deleted When a VRF gets deleted - e.g., networking restart or ifdown of the VRF - but has associated FRR configuration, additional cleanup of all dynamic data pertaining to this VRF is necessary. This includes the routing tables, next hop tables, temporary queues for this VRF etc. Only the FRR configuration for this VRF must be retained. Signed-off-by: Vivek Venkatraman Reviewed-by: Don Slice Reviewed-by: Mitesh Kanjariya Reviewed-by: Donald Sharp Ticket: CM-19148 Reviewed By: CCR-7030 Testing Done: 1. Manual testing - This scenario and EVPN configuration 2. Various smoke tests - vrf, bgp, pim, l3-smoke --- zebra/zebra_vrf.c | 132 +++++++++++++++++++++++++++++++++------------- 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 6c9171c95c..54c9f573c9 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) { @@ -101,6 +106,7 @@ 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; @@ -115,6 +121,20 @@ static int zebra_vrf_enable(struct vrf *vrf) */ 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++) { @@ -152,9 +172,12 @@ 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; assert(zvrf); if (IS_ZEBRA_DEBUG_EVENT) @@ -182,33 +205,74 @@ static int zebra_vrf_disable(struct vrf *vrf) */ zebra_vrf_delete_update(zvrf); - /* uninstall all routes */ - if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) { - struct interface *ifp; + /* If asked to retain routes, there's nothing more to do. */ + if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) + return 0; - for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; - safi++) - rib_close_table(zvrf->table[afi][safi]); + /* 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]); + 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; } - /* Cleanup Vxlan, MPLS and PW tables. */ - zebra_vxlan_cleanup_tables(zvrf); - zebra_mpls_cleanup_tables(zvrf); - zebra_pw_exit(zvrf); + 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; + } - FOR_ALL_INTERFACES (vrf, ifp) - if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); + 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; @@ -234,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); @@ -255,16 +318,17 @@ static int zebra_vrf_delete(struct vrf *vrf) 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; @@ -379,9 +443,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 @@ -389,14 +453,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); From b3628c709593f4db9a062ff304644817b42c99ff Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 4 Jan 2018 17:58:29 -0800 Subject: [PATCH 23/29] bgpd: Fix EVPN type-5 route display Signed-off-by: Vivek Venkatraman Ticket: CM-19131 Reviewed By: None (trivial) Testing Done: Manual --- bgpd/bgp_evpn.c | 2 +- bgpd/bgp_evpn_vty.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 4e40daadb6..35703a7591 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -3624,7 +3624,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) ? diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 56c138ae8c..bd42ccdecf 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -331,7 +331,8 @@ 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); } @@ -2168,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; } From faafdfa8381e3b65711ee8a4473cd113f9904798 Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 5 Jan 2018 12:41:25 -0800 Subject: [PATCH 24/29] bgpd: Fix spurious error messages in EVPN type-5 route injection/withdraw Ensure that spurious error messages are not generated in a non-EVPN configuration when routes in a VRF get deleted or added. Also, check on EVPN advertisement being enabled before walking VRF routing table. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Ticket: CM-19206 Reviewed By: CCR-7073 Testing Done: 1. Recreate errors and validate fix 2. Type-5 route related testing - new routes, neighbor flap etc. --- bgpd/bgp_evpn.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 35703a7591..438b29b4ef 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1082,7 +1082,7 @@ 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 - use the source attr, if * present, else treat as locally originated. @@ -1362,7 +1362,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, @@ -3204,6 +3204,10 @@ void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p, 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; + build_type5_prefix_from_ip_prefix(&evp, p); ret = delete_evpn_type5_route(bgp_vrf, &evp); if (ret) { @@ -3222,6 +3226,7 @@ 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; @@ -3245,6 +3250,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, 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; @@ -3272,6 +3278,10 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, 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)) { /* Need to identify the "selected" route entry to use its From 317f1fe02fa8a6fea0fe9530078edf54335f3228 Mon Sep 17 00:00:00 2001 From: mitesh Date: Thu, 18 Jan 2018 10:27:26 -0800 Subject: [PATCH 25/29] zebra/bgpd: fix compilation issues Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 5 ++--- bgpd/bgp_route.c | 2 +- bgpd/rfapi/rfapi.c | 2 +- bgpd/rfapi/rfapi_import.c | 6 +++--- bgpd/rfapi/rfapi_rib.c | 2 +- bgpd/rfapi/rfapi_vty.c | 6 +++--- bgpd/rfapi/vnc_export_bgp.c | 26 +++++++++++++------------- bgpd/rfapi/vnc_import_bgp.c | 19 ++++++++++--------- zebra/zebra_vty.c | 6 ++++-- zebra/zebra_vxlan.c | 2 +- 10 files changed, 39 insertions(+), 37 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 438b29b4ef..8ad8dc8ee2 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1274,7 +1274,7 @@ 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.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); @@ -3522,7 +3522,6 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels, char *buf, int len) { - vni_t vni; vni_t vni1, vni2; vni1 = label2vni(label); @@ -4202,7 +4201,7 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, zlog_err( "%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)), diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5ed1b42407..36e0c92482 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4472,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. */ 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 37ca5edc96..36100d5429 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 a37e705612..e88dd9399c 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -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/zebra/zebra_vty.c b/zebra/zebra_vty.c index fc4e37f0f9..bc6a18d3b5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2290,7 +2290,7 @@ DEFUN (default_vrf_vni_mapping, if (!zvrf) return CMD_WARNING; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, 1); + 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; @@ -2315,7 +2315,7 @@ DEFUN (no_default_vrf_vni_mapping, if (!zvrf) return CMD_WARNING; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, 0); + 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; @@ -2339,6 +2339,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); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index c05abc3528..750dfc4ea8 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3793,7 +3793,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct stream *s = NULL; char buf[PREFIX_STRLEN]; - client = zebra_find_client(ZEBRA_ROUTE_BGP); + client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ if (!client) return 0; From 22bd3e94979d0c42e9318d96bced01e807b1b7ce Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 6 Dec 2017 15:19:11 -0800 Subject: [PATCH 26/29] *: Refine the notion of a configured VRF in FRR Refine the notion of what FRR considers as "configured" VRF. It is no longer based on user just typing "vrf FOO" but when something is actually configured against that VRF. Right now, in zebra, the only configuration against a VRF are static IP routes and EVPN L3 VNI. Whenever a configuration is removed, check and clear the "configured" flag if there is no other configuration for this VRF. When user attempts to configure a static route and the VRF doesn't exist, a VRF is created; the VRF is only active when also defined in the kernel. Updates: 8b73ea7bd479030418ca06eef59d0648d913b620 Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Don Slice Ticket: CM-10139, CM-18553 Reviewed By: CCR-7019 Testing Done: 1. Manual testing for L3 VNI and static routes - FRR restart, networking restart etc. 2. 'vrf' smoke --- lib/vrf.c | 3 --- lib/vrf.h | 14 +++++++++++++- zebra/zebra_vrf.c | 38 +++++++++++++++++++++++++++++++++++--- zebra/zebra_vrf.h | 1 + zebra/zebra_vty.c | 44 ++++++++++++++++++++++++++++++++++++++------ zebra/zebra_vxlan.c | 2 +- 6 files changed, 88 insertions(+), 14 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index 23eaa042ec..2e15fa2f5c 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -462,9 +462,6 @@ DEFUN_NOSH (vrf, vrfp = vrf_get(VRF_UNKNOWN, vrfname); - /* Mark as user configured. */ - SET_FLAG(vrfp->status, VRF_CONFIGURED); - VTY_PUSH_CONTEXT(VRF_NODE, vrfp); return CMD_SUCCESS; diff --git a/lib/vrf.h b/lib/vrf.h index 89d2316354..99c048c702 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -76,7 +76,7 @@ struct vrf { /* Zebra internal VRF status */ u_char status; #define VRF_ACTIVE (1 << 0) /* VRF is up in kernel */ -#define VRF_CONFIGURED (1 << 1) /* VRF is configured by user in frr */ +#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */ /* Interfaces belonging to this VRF */ struct if_name_head ifaces_by_name; @@ -134,6 +134,18 @@ 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/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 54c9f573c9..4310bd394d 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -351,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. */ @@ -565,14 +596,15 @@ static int vrf_config_write(struct vty *vty) 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 bc6a18d3b5..89ae1e81c3 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, @@ -2269,6 +2295,8 @@ 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"); } @@ -2372,6 +2400,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; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 750dfc4ea8..fb1aebecc3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3801,7 +3801,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); stream_put(s, p, sizeof(struct prefix)); /* Write packet size. */ From 6b11bd8d3f6f713c939a873c7c17213c1e7889e1 Mon Sep 17 00:00:00 2001 From: mitesh Date: Wed, 24 Jan 2018 14:03:05 -0800 Subject: [PATCH 27/29] bgpd: fix SA issues Signed-off-by: Mitesh KAnjariya --- bgpd/bgp_evpn.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 8ad8dc8ee2..3ef563c37c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2880,7 +2880,10 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, if (psize) { num_labels++; memcpy(&label[1], pfx, BGP_LABEL_BYTES); - pfx += 3; + /* + * If in future, we are required to access additional fields, + * we MUST increment pfx by 3 in before reading the next field + */ } /* Process the route. */ @@ -3036,7 +3039,11 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, /* Get the VNI (in MPLS label field). Stored as bytes here. */ memset(&label, 0, sizeof(label)); memcpy(&label, pfx, BGP_LABEL_BYTES); - pfx += 3; + + /* + * If in future, we are required to access additional fields, + * we MUST increment pfx by 3 in before reading the next field + */ /* Process the route. */ if (!withdraw) From 1b817c78e6991e006c9c9d44cf678c1e57b9f6fa Mon Sep 17 00:00:00 2001 From: mitesh Date: Mon, 5 Feb 2018 13:24:57 -0800 Subject: [PATCH 28/29] bgpd: use BGP_LABEL_BYTES instead of a mogic number '3' While processing the type-2 evpn route nlri, increment the pointer by BGP_LABEL_BYTES instead of '3' Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 3ef563c37c..7724a0eec8 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2874,7 +2874,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, num_labels++; memset(label, 0, sizeof(label)); memcpy(&label[0], pfx, BGP_LABEL_BYTES); - pfx += 3; + pfx += BGP_LABEL_BYTES; psize -= (33 + ipaddr_len); /* Do we have a second VNI? */ if (psize) { @@ -2882,7 +2882,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, memcpy(&label[1], pfx, BGP_LABEL_BYTES); /* * If in future, we are required to access additional fields, - * we MUST increment pfx by 3 in before reading the next field + * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field */ } @@ -3042,7 +3042,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, /* * If in future, we are required to access additional fields, - * we MUST increment pfx by 3 in before reading the next field + * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field */ /* Process the route. */ From 9d00a48754440cc9d4674e9b9405642edd983f0f Mon Sep 17 00:00:00 2001 From: mitesh Date: Mon, 5 Feb 2018 13:29:52 -0800 Subject: [PATCH 29/29] bgpd: allow evpn safi under vrf instance Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_vty.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3ef5e993fc..d3edc89985 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6103,7 +6103,8 @@ 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) { + 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; @@ -6126,7 +6127,8 @@ 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) { + 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;