]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #1654 from mkanjari/evpn-symm-routing-enhancements
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 8 Feb 2018 10:46:29 +0000 (11:46 +0100)
committerGitHub <noreply@github.com>
Thu, 8 Feb 2018 10:46:29 +0000 (11:46 +0100)
Evpn symmetric routing enhancements

44 files changed:
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_attr_evpn.c
bgpd/bgp_attr_evpn.h
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_ecommunity.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_label.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_rib.c
bgpd/rfapi/rfapi_vty.c
bgpd/rfapi/vnc_export_bgp.c
bgpd/rfapi/vnc_import_bgp.c
lib/log.c
lib/vrf.c
lib/vrf.h
lib/zclient.c
lib/zclient.h
vtysh/vtysh_config.c
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_ns.c
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_null.c
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index 206d91bfe9115a4cb8a363d2fb22dd67d2b1e813..3f3acbe0e2923db2638035a707dc494883508cb5 100644 (file)
@@ -1876,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
        attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
        attr->sticky = sticky;
 
+       /* Check if this is a Gateway MAC-IP advertisement */
+       attr->default_gw = bgp_attr_default_gw(attr);
+
        /* Extract the Rmac, if any */
        bgp_attr_rmac(attr, &attr->rmac);
 
@@ -2698,8 +2701,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
 
 void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                              struct prefix *p, struct prefix_rd *prd,
-                             mpls_label_t *label, int addpath_encode,
-                             u_int32_t addpath_tx_id, struct attr *attr)
+                             mpls_label_t *label, u_int32_t num_labels,
+                             int addpath_encode, u_int32_t addpath_tx_id,
+                             struct attr *attr)
 {
        if (safi == SAFI_MPLS_VPN) {
                if (addpath_encode)
@@ -2711,8 +2715,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
        } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
                /* EVPN prefix - contents depend on type */
-               bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode,
-                                      addpath_tx_id);
+               bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
+                                      attr, addpath_encode, addpath_tx_id);
        } else if (safi == SAFI_LABELED_UNICAST) {
                /* Prefix write with label. */
                stream_put_labeled_prefix(s, p, label);
@@ -2840,8 +2844,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
                                struct bpacket_attr_vec_arr *vecarr,
                                struct prefix *p, afi_t afi, safi_t safi,
                                struct peer *from, struct prefix_rd *prd,
-                               mpls_label_t *label, int addpath_encode,
-                               u_int32_t addpath_tx_id)
+                               mpls_label_t *label, u_int32_t num_labels,
+                               int addpath_encode, u_int32_t addpath_tx_id)
 {
        size_t cp;
        size_t aspath_sizep;
@@ -2863,7 +2867,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
 
                mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
                                                        vecarr, attr);
-               bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+               bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
+                                        label, num_labels,
                                         addpath_encode, addpath_tx_id, attr);
                bgp_packet_mpattr_end(s, mpattrlen_pos);
        }
@@ -3295,15 +3300,19 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
 
 void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
                                 safi_t safi, struct prefix_rd *prd,
-                                mpls_label_t *label, int addpath_encode,
-                                u_int32_t addpath_tx_id, struct attr *attr)
+                                mpls_label_t *label, u_int32_t num_labels,
+                                int addpath_encode, u_int32_t addpath_tx_id,
+                                struct attr *attr)
 {
        u_char wlabel[3] = {0x80, 0x00, 0x00};
 
-       if (safi == SAFI_LABELED_UNICAST)
+       if (safi == SAFI_LABELED_UNICAST) {
                label = (mpls_label_t *)wlabel;
+               num_labels = 1;
+       }
 
-       return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+       return bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
+                                       label, num_labels,
                                        addpath_encode, addpath_tx_id, attr);
 }
 
index 1de1bee0f9d69fea750edecb6101e668cccf95bc..1b1471a198974cdb7e4de38639225e1ba1a6bad4 100644 (file)
@@ -162,6 +162,9 @@ struct attr {
        /* Static MAC for EVPN */
        u_char sticky;
 
+       /* Flag for default gateway extended community in EVPN */
+       u_char default_gw;
+
        /* route tag */
        route_tag_t tag;
 
@@ -257,7 +260,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
                                       struct bpacket_attr_vec_arr *vecarr,
                                       struct prefix *, afi_t, safi_t,
                                       struct peer *, struct prefix_rd *,
-                                      mpls_label_t *, int, u_int32_t);
+                                      mpls_label_t *, u_int32_t,
+                                      int, u_int32_t);
 extern void bgp_dump_routes_attr(struct stream *, struct attr *,
                                 struct prefix *);
 extern int attrhash_cmp(const void *, const void *);
@@ -305,7 +309,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
                                      struct attr *attr);
 extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                                     struct prefix *p, struct prefix_rd *prd,
-                                    mpls_label_t *label, int addpath_encode,
+                                    mpls_label_t *label, u_int32_t num_labels,
+                                    int addpath_encode,
                                     u_int32_t addpath_tx_id, struct attr *);
 extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
                                            struct prefix *p);
@@ -315,7 +320,8 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
                                         safi_t safi);
 extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
                                        afi_t afi, safi_t safi,
-                                       struct prefix_rd *prd, mpls_label_t *,
+                                       struct prefix_rd *prd,
+                                       mpls_label_t *, u_int32_t,
                                        int, u_int32_t, struct attr *);
 extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
 
index eaa4e329d455b616ffd71ac6d2c22fadb05a8a81..e74fa5a2be5876ae9383e166a23dfabe9f777fb7 100644 (file)
@@ -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.
index 8b55cb30020bf4f7a168afad88b6adc43f90035e..a211da8d2f0d746f23823c98bd0c2d8e1b41a0b3 100644 (file)
@@ -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 */
index 45ac8e68597fbf1ccabf712d5c77d0270acbc503..b08522b68bd67e08884cd2f78ead7d262033896f 100644 (file)
@@ -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)
index 5fe19b162b88d80c25f18a5d6cac5b685e1c4dca..7c773cfafbf42f6d0e1e52ae137e108b950d6673 100644 (file)
@@ -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);
index 9caf38d569b35a355f5f5fb60870d1961873c151..7dafde51a120ad5f57f1b384096773d749c4f97c 100644 (file)
@@ -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) {
index 824b72b240ad4c2196d75fad9f9d6ff3d496f669..c7d5f8d1118c785b30704f475dfec5e0afb75594 100644 (file)
@@ -484,7 +484,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
 static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
                                       struct prefix_evpn *p,
                                       struct in_addr remote_vtep_ip, int add,
-                                      u_char sticky)
+                                      u_char flags)
 {
        struct stream *s;
        int ipa_len;
@@ -519,18 +519,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
        }
        stream_put_in_addr(s, &remote_vtep_ip);
 
-       /* TX MAC sticky status */
+       /* TX flags - MAC sticky status and/or gateway mac */
        if (add)
-               stream_putc(s, sticky);
+               stream_putc(s, flags);
 
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (bgp_debug_zebra(NULL))
-               zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s",
+               zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s",
                           add ? "ADD" : "DEL", vpn->vni,
-                          sticky ? "sticky " : "",
                           prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)),
                           ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)),
+                          flags,
                           inet_ntop(AF_INET, &remote_vtep_ip, buf2,
                                     sizeof(buf2)));
 
@@ -640,9 +640,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
 {
        struct ecommunity ecom_encap;
        struct ecommunity ecom_sticky;
+       struct ecommunity ecom_default_gw;
        struct ecommunity ecom_rmac;
        struct ecommunity_val eval;
        struct ecommunity_val eval_sticky;
+       struct ecommunity_val eval_default_gw;
        struct ecommunity_val eval_rmac;
        bgp_encap_types tnl_type;
        struct listnode *node, *nnode;
@@ -697,6 +699,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
                                                    &ecom_rmac);
        }
 
+       if (attr->default_gw) {
+               memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
+               encode_default_gw_extcomm(&eval_default_gw);
+               ecom_default_gw.size = 1;
+               ecom_default_gw.val = (uint8_t *)eval_default_gw.val;
+               attr->ecommunity = ecommunity_merge(attr->ecommunity,
+                                                   &ecom_default_gw);
+       }
+
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
 }
 
@@ -754,13 +765,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
 /* Install EVPN route into zebra. */
 static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
                              struct prefix_evpn *p,
-                             struct in_addr remote_vtep_ip, u_char sticky)
+                             struct in_addr remote_vtep_ip, u_char flags)
 {
        int ret;
 
        if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
                ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
-                                                 1, sticky);
+                                                 1, flags);
        else
                ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
 
@@ -831,6 +842,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
        int ret = 0;
+       u_char                  flags = 0;
 
        /* Compute the best path. */
        bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
@@ -848,11 +860,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
            && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
            && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)
            && !bgp->addpath_tx_used[afi][safi]) {
-               if (bgp_zebra_has_route_changed(rn, old_select))
+               if (bgp_zebra_has_route_changed(rn, old_select)) {
+                       if (old_select->attr->sticky)
+                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+                       if (old_select->attr->default_gw)
+                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
                        ret = evpn_zebra_install(bgp, vpn,
                                                 (struct prefix_evpn *)&rn->p,
                                                 old_select->attr->nexthop,
-                                                old_select->attr->sticky);
+                                                flags);
+               }
                UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
                bgp_zebra_clear_route_change_flags(rn);
                return ret;
@@ -877,9 +894,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
 
        if (new_select && new_select->type == ZEBRA_ROUTE_BGP
            && new_select->sub_type == BGP_ROUTE_NORMAL) {
+               flags = 0;
+               if (new_select->attr->sticky)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+               if (new_select->attr->default_gw)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
                ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
                                         new_select->attr->nexthop,
-                                        new_select->attr->sticky);
+                                        flags);
                /* If an old best existed and it was a "local" route, the only
                 * reason
                 * it would be supplanted is due to MAC mobility procedures. So,
@@ -909,6 +931,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
        return ret;
 }
 
+/*
+ * Return true if the local ri for this rn is of type gateway mac
+ */
+static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn)
+{
+       struct bgp_info         *tmp_ri = NULL;
+       struct bgp_info         *local_ri = NULL;
+
+       local_ri = NULL;
+       for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
+               if (tmp_ri->peer == bgp->peer_self
+                   && tmp_ri->type == ZEBRA_ROUTE_BGP
+                   && tmp_ri->sub_type == BGP_ROUTE_STATIC)
+                       local_ri = tmp_ri;
+       }
+
+       if (!local_ri)
+               return 0;
+
+       return local_ri->attr->default_gw;
+}
+
 
 /*
  * Return true if the local ri for this rn has sticky set
@@ -968,10 +1012,11 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
                               bgp_def->peer_self, attr_new, rn);
                SET_FLAG(ri->flags, BGP_INFO_VALID);
 
-               /* L3-VNI goes in the label2 field */
+               /* Type-5 routes advertise the L3-VNI */
                bgp_info_extra_get(ri);
                vni2label(bgp_vrf->l3vni, &label);
-               memcpy(&ri->extra->label2, &label, BGP_LABEL_BYTES);
+               memcpy(&ri->extra->label, &label, sizeof(label));
+               ri->extra->num_labels = 1;
 
                /* add the route entry to route node*/
                bgp_info_add(rn, ri);
@@ -1003,7 +1048,8 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
 
 /* update evpn type-5 route entry */
 static int update_evpn_type5_route(struct bgp *bgp_vrf,
-                                  struct prefix_evpn *evp)
+                                  struct prefix_evpn *evp,
+                                  struct attr* src_attr)
 {
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
@@ -1014,11 +1060,18 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
 
        bgp_def = bgp_get_default();
        if (!bgp_def)
-               return -1;
+               return 0;
 
-       /* build path attribute for this route */
-       memset(&attr, 0, sizeof(struct attr));
-       bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
+       /* Build path attribute for this route - use the source attr, if
+        * present, else treat as locally originated.
+        */
+       if (src_attr)
+               bgp_attr_dup(&attr, src_attr);
+       else {
+               memset(&attr, 0, sizeof(struct attr));
+               bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
+       }
+       /* Set nexthop to ourselves and fill in the Router MAC. */
        attr.nexthop = bgp_vrf->originator_ip;
        attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
@@ -1045,7 +1098,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
        }
 
        /* uninten temporary */
-       aspath_unintern(&attr.aspath);
+       if (!src_attr)
+               aspath_unintern(&attr.aspath);
        return 0;
 }
 
@@ -1061,11 +1115,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        struct bgp_info *tmp_ri;
        struct bgp_info *local_ri, *remote_ri;
        struct attr *attr_new;
-       mpls_label_t label = MPLS_INVALID_LABEL;
+       mpls_label_t label[BGP_MAX_LABELS];
+       u_int32_t num_labels = 1;
        int route_change = 1;
        u_char sticky = 0;
+       struct prefix_evpn *evp;
 
        *ri = NULL;
+       evp = (struct prefix_evpn *)&rn->p;
+       memset(&label, 0, sizeof(label));
 
        /* See if this is an update of an existing route, or a new add. Also,
         * identify if already known from remote, and if so, the one with the
@@ -1107,7 +1165,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                 * SVI) advertised in EVPN.
                 * This will ensure that local routes are preferred for g/w macs
                 */
-               if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
+               if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
                        u_int32_t cur_seqnum;
 
                        /* Add MM extended community to route. */
@@ -1130,9 +1188,20 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                bgp_info_extra_get(tmp_ri);
 
                /* The VNI goes into the 'label' field of the route */
-               vni2label(vpn->vni, &label);
+               vni2label(vpn->vni, &label[0]);
+               /* Type-2 routes may carry a second VNI - the L3-VNI */
+               if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+                       vni_t l3vni;
+
+                       l3vni = bgpevpn_get_l3vni(vpn);
+                       if (l3vni) {
+                               vni2label(l3vni, &label[1]);
+                               num_labels++;
+                       }
+               }
 
-               memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES);
+               memcpy(&tmp_ri->extra->label, label, sizeof(label));
+               tmp_ri->extra->num_labels = num_labels;
                bgp_info_add(rn, tmp_ri);
        } else {
                tmp_ri = local_ri;
@@ -1183,8 +1252,9 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        attr.nexthop = vpn->originator_ip;
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
-       attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
-  attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
+       attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0;
+       attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
+       attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
        bgpevpn_get_rmac(vpn, &attr.rmac);
        vni2label(vpn->vni, &(attr.label));
 
@@ -1270,7 +1340,7 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf,
 
        bgp_def = bgp_get_default();
        if (!bgp_def)
-               return -1;
+               return 0;
 
        /* locate the global route entry for this type-5 prefix */
        rn = bgp_afi_node_lookup(bgp_def->rib[afi][safi], afi, safi,
@@ -1372,22 +1442,27 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
        struct bgp_info *ri;
        struct attr attr;
        struct attr attr_sticky;
+       struct attr attr_def_gw;
        struct attr attr_ip6;
        struct attr attr_sticky_ip6;
+       struct attr attr_def_gw_ip6;
        struct attr *attr_new;
 
        afi = AFI_L2VPN;
        safi = SAFI_EVPN;
        memset(&attr, 0, sizeof(struct attr));
        memset(&attr_sticky, 0, sizeof(struct attr));
+       memset(&attr_def_gw, 0, sizeof(struct attr));
        memset(&attr_ip6, 0, sizeof(struct attr));
        memset(&attr_sticky_ip6, 0, sizeof(struct attr));
+       memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
 
        /* Build path-attribute - all type-2 routes for this VNI will share the
         * same path attribute.
         */
        bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
        bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP);
        attr.nexthop = vpn->originator_ip;
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
@@ -1397,8 +1472,14 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
        attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        attr_sticky.sticky = 1;
        bgpevpn_get_rmac(vpn, &attr_sticky.rmac);
+       attr_def_gw.nexthop = vpn->originator_ip;
+       attr_def_gw.mp_nexthop_global_in = vpn->originator_ip;
+       attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       attr_def_gw.default_gw = 1;
+       bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
        bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
        bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
        attr_ip6.nexthop = vpn->originator_ip;
        attr_ip6.mp_nexthop_global_in = vpn->originator_ip;
        attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
@@ -1408,12 +1489,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
        attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        attr_sticky_ip6.sticky = 1;
        bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
+       attr_def_gw_ip6.nexthop = vpn->originator_ip;
+       attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
+       attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       attr_def_gw_ip6.default_gw = 1;
+       bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
 
        /* Set up RT, ENCAP and sticky MAC extended community. */
        build_evpn_route_extcomm(vpn, &attr, AFI_IP);
        build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
+       build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
        build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
        build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
+       build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
 
        /* Walk this VNI's route table and update local type-2 routes. For any
         * routes updated, update corresponding entry in the global table too.
@@ -1432,6 +1520,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &attr_sticky, 0, 1,
                                                        &ri, 0);
+                       else if (evpn_route_is_def_gw(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_def_gw, 0, 1,
+                                                       &ri, 0);
                        else
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &attr, 0, 1, &ri, 0);
@@ -1440,6 +1532,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &attr_sticky_ip6, 0, 1,
                                                        &ri, 0);
+                       else if (evpn_route_is_def_gw(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_def_gw_ip6, 0, 1,
+                                                       &ri, 0);
                        else
                                update_evpn_route_entry(bgp, vpn, afi, safi, rn,
                                                        &attr_ip6, 0, 1,
@@ -1474,7 +1570,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
 
        /* Unintern temporary. */
        aspath_unintern(&attr.aspath);
+       aspath_unintern(&attr_ip6.aspath);
        aspath_unintern(&attr_sticky.aspath);
+       aspath_unintern(&attr_sticky_ip6.aspath);
+       aspath_unintern(&attr_def_gw.aspath);
+       aspath_unintern(&attr_def_gw_ip6.aspath);
 
        return 0;
 }
@@ -1717,9 +1817,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
                SET_FLAG(ri->flags, BGP_INFO_VALID);
                bgp_info_extra_get(ri);
                ri->extra->parent = parent_ri;
-               if (parent_ri->extra)
+               if (parent_ri->extra) {
                        memcpy(&ri->extra->label, &parent_ri->extra->label,
-                              BGP_LABEL_BYTES);
+                              sizeof(ri->extra->label));
+                       ri->extra->num_labels = parent_ri->extra->num_labels;
+               }
                bgp_info_add(rn, ri);
        } else {
                if (attrhash_cmp(ri->attr, parent_ri->attr)
@@ -1783,9 +1885,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                SET_FLAG(ri->flags, BGP_INFO_VALID);
                bgp_info_extra_get(ri);
                ri->extra->parent = parent_ri;
-               if (parent_ri->extra)
+               if (parent_ri->extra) {
                        memcpy(&ri->extra->label, &parent_ri->extra->label,
-                              BGP_LABEL_BYTES);
+                              sizeof(ri->extra->label));
+                       ri->extra->num_labels = parent_ri->extra->num_labels;
+               }
                bgp_info_add(rn, ri);
        } else {
                if (attrhash_cmp(ri->attr, parent_ri->attr)
@@ -2675,7 +2779,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        struct prefix_evpn p;
        u_char ipaddr_len;
        u_char macaddr_len;
-       mpls_label_t *label_pnt;
+       mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
+       u_int32_t num_labels = 0;
        int ret;
 
        /* Type-2 route should be either 33, 37 or 49 bytes or an
@@ -2743,19 +2848,31 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        }
        pfx += ipaddr_len;
 
-       /* Get the VNI (in MPLS label field). */
-       /* Note: We ignore the second VNI, if any. */
-       label_pnt = (mpls_label_t *)pfx;
+       /* Get the VNI(s). Stored as bytes here. */
+       num_labels++;
+       memset(label, 0, sizeof(label));
+       memcpy(&label[0], pfx, BGP_LABEL_BYTES);
+       pfx += BGP_LABEL_BYTES;
+       psize -= (33 + ipaddr_len);
+       /* Do we have a second VNI? */
+       if (psize) {
+               num_labels++;
+               memcpy(&label[1], pfx, BGP_LABEL_BYTES);
+               /*
+                * If in future, we are required to access additional fields,
+                * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
+                */
+       }
 
        /* Process the route. */
        if (attr)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, label_pnt, 0, NULL);
+                                &prd, &label[0], num_labels, 0, NULL);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, label_pnt, NULL);
+                                  &prd, &label[0], num_labels, NULL);
        return ret;
 }
 
@@ -2811,11 +2928,11 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
        if (attr)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, NULL, 0, NULL);
+                                &prd, NULL, 0, 0, NULL);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, NULL, NULL);
+                                  &prd, NULL, 0, NULL);
        return ret;
 }
 
@@ -2831,7 +2948,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        struct bgp_route_evpn evpn;
        u_char ippfx_len;
        u_int32_t eth_tag;
-       mpls_label_t *label_pnt;
+       mpls_label_t label; /* holds the VNI as in the packet */
        int ret;
 
        /* Type-5 route should be 34 or 58 bytes:
@@ -2897,23 +3014,31 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
                pfx += 16;
        }
 
-       label_pnt = (mpls_label_t *)pfx;
+       /* Get the VNI (in MPLS label field). Stored as bytes here. */
+       memset(&label, 0, sizeof(label));
+       memcpy(&label, pfx, BGP_LABEL_BYTES);
+
+       /*
+        * If in future, we are required to access additional fields,
+        * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
+        */
 
        /* Process the route. */
        if (!withdraw)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, label_pnt, 0, &evpn);
+                                &prd, &label, 1, 0, &evpn);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, label_pnt, &evpn);
+                                  &prd, &label, 1, &evpn);
 
        return ret;
 }
 
 static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
-                                    struct prefix_rd *prd, mpls_label_t *label,
+                                    struct prefix_rd *prd,
+                                    mpls_label_t *label, u_int32_t num_labels,
                                     struct attr *attr)
 {
        int len;
@@ -2958,7 +3083,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
                        stream_put(s, &temp, 16);
        }
 
-       if (label)
+       if (num_labels)
                stream_put(s, label, 3);
        else
                stream_put3(s, 0);
@@ -3057,20 +3182,24 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
  */
 
 /* withdraw type-5 route corresponding to ip prefix */
-void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
                                   afi_t afi, safi_t safi)
 {
        int ret = 0;
        struct prefix_evpn evp;
        char buf[PREFIX_STRLEN];
 
-       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       /* NOTE: Check needed as this is called per-route also. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       build_type5_prefix_from_ip_prefix(&evp, p);
        ret = delete_evpn_type5_route(bgp_vrf, &evp);
        if (ret) {
                zlog_err(
                         "%u failed to delete type-5 route for prefix %s in vrf %s",
                         bgp_vrf->vrf_id,
-                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        prefix2str(p, buf, sizeof(buf)),
                         vrf_id_to_name(bgp_vrf->vrf_id));
        }
 }
@@ -3082,54 +3211,77 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
        struct bgp_table *table = NULL;
        struct bgp_node *rn = NULL;
 
+       /* Bail out early if we don't have to advertise type-5 routes. */
        if (!advertise_type5_routes(bgp_vrf, afi))
                return;
 
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi);
+               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
 
 }
 
-/* advertise ip prefix as type-5 route*/
-void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+/*
+ * Advertise IP prefix as type-5 route. The afi/safi and src_attr passed
+ * to this function correspond to those of the source IP prefix (best
+ * path in the case of the attr. In the case of a local prefix (when we
+ * are advertising local subnets), the src_attr will be NULL.
+ */
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
+                                   struct attr *src_attr,
                                    afi_t afi, safi_t safi)
 {
        int ret = 0;
        struct prefix_evpn evp;
        char buf[PREFIX_STRLEN];
 
+       /* NOTE: Check needed as this is called per-route also. */
        if (!advertise_type5_routes(bgp_vrf, afi))
                return;
 
-       if (!rn->info)
-               return;
-
        /* only advertise subnet routes as type-5 */
-       if (is_host_route(&rn->p))
+       if (is_host_route(p))
                return;
 
-       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
-       ret = update_evpn_type5_route(bgp_vrf, &evp);
-       if (ret) {
+       build_type5_prefix_from_ip_prefix(&evp, p);
+       ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
+       if (ret)
                zlog_err(
-                        "%u failed to create type-5 route for prefix %s in vrf %s",
+                        "%u: Failed to create type-5 route for prefix %s",
                         bgp_vrf->vrf_id,
-                        prefix2str(&rn->p, buf, sizeof(buf)),
-                        vrf_id_to_name(bgp_vrf->vrf_id));
-       }
+                        prefix2str(p, buf, sizeof(buf)));
 }
 
-/* advertise all type-5 routes for an address family */
+/* Inject all prefixes of a particular address-family (currently, IPv4 or
+ * IPv6 unicast) into EVPN as type-5 routes. This is invoked when the
+ * advertisement is enabled.
+ */
 void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
                                     afi_t afi, safi_t safi)
 {
        struct bgp_table *table = NULL;
        struct bgp_node *rn = NULL;
+       struct bgp_info *ri;
+
+       /* Bail out early if we don't have to advertise type-5 routes. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
 
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               /* Need to identify the "selected" route entry to use its
+                * attribute.
+                * TODO: Support for AddPath for EVPN.
+                */
+               for (ri = rn->info; ri; ri = ri->next) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) {
+                               bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p,
+                                                              ri->attr,
+                                                              afi, safi);
+                               break;
+                       }
+               }
+       }
 }
 
 void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
@@ -3350,14 +3502,19 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn)
 }
 
 /*
- * Function to display "tag" in route as a VNI.
+ * TODO: Hardcoded for a maximum of 2 VNIs right now
  */
-char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len)
+char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
+                        char *buf, int len)
 {
-       vni_t vni;
+       vni_t vni1, vni2;
 
-       vni = label2vni(label);
-       snprintf(buf, len, "%u", vni);
+       vni1 = label2vni(label);
+       if (num_labels == 2) {
+               vni2 = label2vni(label+1);
+               snprintf(buf, len, "%u/%u", vni1, vni2);
+       } else
+               snprintf(buf, len, "%u", vni1);
        return buf;
 }
 
@@ -3461,7 +3618,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
                                           PREFIX2STR_BUFFER));
                }
        } else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
-               snprintf(buf, len, "[%d]:[0]:[%d]:[%s]",
+               snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
                         p->prefix.route_type,
                         p->prefix.ip_prefix_length,
                         IS_EVPN_PREFIX_IPADDR_V4(p) ?
@@ -3480,12 +3637,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
  * Encode EVPN prefix in Update (MP_REACH)
  */
 void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
-                           struct prefix_rd *prd, mpls_label_t *label,
+                           struct prefix_rd *prd,
+                           mpls_label_t *label, u_int32_t num_labels,
                            struct attr *attr, int addpath_encode,
                            u_int32_t addpath_tx_id)
 {
        struct prefix_evpn *evp = (struct prefix_evpn *)p;
-       int ipa_len = 0;
+       int len, ipa_len = 0;
 
        if (addpath_encode)
                stream_putl(s, addpath_tx_id);
@@ -3499,18 +3657,24 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
                        ipa_len = IPV4_MAX_BYTELEN;
                else if (IS_EVPN_PREFIX_IPADDR_V6(evp))
                        ipa_len = IPV6_MAX_BYTELEN;
-               stream_putc(s, 33 + ipa_len);       // 1 VNI
+               /* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */
+               len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3;
+               if (ipa_len && num_labels > 1) /* There are 2 VNIs */
+                       len += 3;
+               stream_putc(s, len);
                stream_put(s, prd->val, 8);      /* RD */
                stream_put(s, 0, 10);               /* ESI */
                stream_putl(s, 0);                  /* Ethernet Tag ID */
                stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
                stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */
                stream_putc(s, 8 * ipa_len);             /* IP address Length */
-               if (ipa_len)
-                       stream_put(s, &evp->prefix.ip.ip.addr,
-                                  ipa_len); /* IP */
-               stream_put(s, label,
-                          BGP_LABEL_BYTES); /* VNI is contained in 'tag' */
+               if (ipa_len) /* IP */
+                       stream_put(s, &evp->prefix.ip.ip.addr, ipa_len);
+               /* 1st label is the L2 VNI */
+               stream_put(s, label, BGP_LABEL_BYTES);
+               /* Include 2nd label (L3 VNI) if advertising MAC+IP */
+               if (ipa_len && num_labels > 1)
+                       stream_put(s, label+1, BGP_LABEL_BYTES);
                break;
 
        case BGP_EVPN_IMET_ROUTE:
@@ -3524,7 +3688,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
 
        case BGP_EVPN_IP_PREFIX_ROUTE:
                /* TODO: AddPath support. */
-               evpn_mpattr_encode_type5(s, p, prd, label, attr);
+               evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr);
                break;
 
        default:
@@ -4020,12 +4184,13 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
                char buf2[INET6_ADDRSTRLEN];
 
                zlog_err(
-                       "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
+                       "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
                        bgp->vrf_id, vpn->vni,
-                       CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
+                       CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "sticky gateway"
                                                                 : "",
                        prefix_mac2str(mac, buf, sizeof(buf)),
-                       ipaddr2str(ip, buf2, sizeof(buf2)));
+                       ipaddr2str(ip, buf2, sizeof(buf2)),
+                       flags);
                return -1;
        }
 
index 9400916845b04374263de3772f004e1077860110..a8dcbc112b1cc18b4313bec527e4f4d0ecd95403 100644 (file)
@@ -34,11 +34,33 @@ static inline int is_evpn_enabled(void)
        return bgp ? bgp->advertise_all_vni : 0;
 }
 
+static inline void vni2label(vni_t vni, mpls_label_t *label)
+{
+       u_char *tag = (u_char *)label;
+
+       tag[0] = (vni >> 16) & 0xFF;
+       tag[1] = (vni >> 8) & 0xFF;
+       tag[2] = vni & 0xFF;
+}
+
+static inline vni_t label2vni(mpls_label_t *label)
+{
+       u_char *tag = (u_char *)label;
+       vni_t vni;
+
+       vni = ((u_int32_t)*tag++ << 16);
+       vni |= (u_int32_t)*tag++ << 8;
+       vni |= (u_int32_t)(*tag & 0xFF);
+
+       return vni;
+}
+
 extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
-                                          struct bgp_node *rn,
+                                          struct prefix *p,
+                                          struct attr *src_attr,
                                           afi_t afi, safi_t safi);
 extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
-                                         struct bgp_node *rn,
+                                         struct prefix *p,
                                          afi_t afi, safi_t safi);
 extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
                                           safi_t safi);
@@ -46,11 +68,13 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
                                            safi_t safi);
 extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
 extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
-extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
+extern char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
+                               char *buf, int len);
 extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
 extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
 extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
-                                  struct prefix_rd *prd, mpls_label_t *label,
+                                  struct prefix_rd *prd,
+                                  mpls_label_t *label, u_int32_t num_labels,
                                   struct attr *attr, int addpath_encode,
                                   u_int32_t addpath_tx_id);
 extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
index 2d52e1995d2bbc6596bf98f43486b7ca1a718ff2..cc0ec82344b3f2c03cad7cc7a4fd1ca1806d82c5 100644 (file)
@@ -65,6 +65,9 @@ struct bgpevpn {
        /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
        u_int8_t advertise_gw_macip;
 
+       /* Flag to indicate if we are advertising subnet for this VNI */
+       u_int8_t advertise_subnet;
+
        /* Id for deriving the RD automatically for this VNI */
        u_int16_t rd_id;
 
@@ -228,26 +231,6 @@ static inline int is_vni_param_configured(struct bgpevpn *vpn)
                || is_export_rt_configured(vpn));
 }
 
-static inline void vni2label(vni_t vni, mpls_label_t *label)
-{
-       u_char *tag = (u_char *)label;
-       tag[0] = (vni >> 16) & 0xFF;
-       tag[1] = (vni >> 8) & 0xFF;
-       tag[2] = vni & 0xFF;
-}
-
-static inline vni_t label2vni(mpls_label_t *label)
-{
-       u_char *tag = (u_char *)label;
-       vni_t vni;
-
-       vni = ((u_int32_t)*tag++ << 16);
-       vni |= (u_int32_t)*tag++ << 8;
-       vni |= (u_int32_t)(*tag & 0xFF);
-
-       return vni;
-}
-
 static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
                                       struct ethaddr *rmac)
 {
@@ -257,6 +240,13 @@ static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
        memcpy(&eval->val[2], rmac, ETH_ALEN);
 }
 
+static inline void encode_default_gw_extcomm(struct ecommunity_val *eval)
+{
+       memset(eval, 0, sizeof(*eval));
+       eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
+       eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW;
+}
+
 static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
                                               struct ecommunity_val *eval)
 {
index b463896c493345f2825bd40a734bc50bb8e18a14..bd42ccdecfddaf86c83c704910bdac7f8ba5f781 100644 (file)
@@ -331,10 +331,88 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
        vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
        vty_out(vty,
                "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
-       vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n");
+       vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
+       vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
        vty_out(vty, "%s", ri_header);
 }
 
+static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
+                         json_object *json)
+{
+       char buf1[INET6_ADDRSTRLEN];
+       char *ecom_str;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+       json_object *json_import_rtl = NULL;
+       json_object *json_export_rtl = NULL;
+
+       json_import_rtl = json_export_rtl = 0;
+
+       if (json) {
+               json_import_rtl = json_object_new_array();
+               json_export_rtl = json_object_new_array();
+               json_object_int_add(json, "vni", bgp_vrf->l3vni);
+               json_object_string_add(json, "type", "L3");
+               json_object_string_add(json, "kernelFlag", "Yes");
+               json_object_string_add(
+                       json, "rd",
+                       prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+               json_object_string_add(json, "originatorIp",
+                                      inet_ntoa(bgp_vrf->originator_ip));
+               json_object_string_add(json, "advertiseGatewayMacip", "n/a");
+       } else {
+               vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
+               vty_out(vty, " (known to the kernel)");
+               vty_out(vty, "\n");
+
+               vty_out(vty, "  Type: %s\n", "L3");
+               vty_out(vty, "  Tenant VRF: %s\n",
+                       vrf_id_to_name(bgp_vrf->vrf_id));
+               vty_out(vty, "  RD: %s\n",
+                       prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+               vty_out(vty, "  Originator IP: %s\n",
+                       inet_ntoa(bgp_vrf->originator_ip));
+               vty_out(vty, "  Advertise-gw-macip : %s\n", "n/a");
+       }
+
+       if (!json)
+               vty_out(vty, "  Import Route Target:\n");
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json)
+                       json_object_array_add(json_import_rtl,
+                                             json_object_new_string(ecom_str));
+               else
+                       vty_out(vty, "    %s\n", ecom_str);
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+       }
+
+       if (json)
+               json_object_object_add(json, "importRts", json_import_rtl);
+       else
+               vty_out(vty, "  Export Route Target:\n");
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json)
+                       json_object_array_add(json_export_rtl,
+                                             json_object_new_string(ecom_str));
+               else
+                       vty_out(vty, "    %s\n", ecom_str);
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+       }
+
+       if (json)
+               json_object_object_add(json, "exportRts", json_export_rtl);
+}
+
 static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
 {
        char buf1[RD_ADDRSTRLEN];
@@ -348,6 +426,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                json_import_rtl = json_object_new_array();
                json_export_rtl = json_object_new_array();
                json_object_int_add(json, "vni", vpn->vni);
+               json_object_string_add(json, "type", "L2");
                json_object_string_add(json, "kernelFlag",
                                       is_vni_live(vpn) ? "Yes" : "No");
                json_object_string_add(
@@ -363,6 +442,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                        vty_out(vty, " (known to the kernel)");
                vty_out(vty, "\n");
 
+               vty_out(vty, "  Type: %s\n", "L2");
                vty_out(vty, "  Tenant-Vrf: %s\n",
                        vrf_id_to_name(vpn->tenant_vrf_id));
                vty_out(vty, "  RD: %s\n",
@@ -570,6 +650,110 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
                json_object_object_add(json, vni_str, json_vni);
 }
 
+static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
+                          json_object *json)
+{
+       json_object *json_vni;
+       json_object *json_import_rtl;
+       json_object *json_export_rtl;
+       char buf1[10];
+       char buf2[INET6_ADDRSTRLEN];
+       char rt_buf[25];
+       char *ecom_str;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+
+       if (!bgp->l3vni)
+               return;
+
+       if (json) {
+               json_vni = json_object_new_object();
+               json_import_rtl = json_object_new_array();
+               json_export_rtl = json_object_new_array();
+       }
+
+       /* if an l3vni is present in bgp it is live */
+       buf1[0] = '\0';
+       sprintf(buf1, "*");
+
+       if (json) {
+               json_object_int_add(json_vni, "vni", bgp->l3vni);
+               json_object_string_add(json_vni, "type", "L3");
+               json_object_string_add(json_vni, "inKernel", "True");
+               json_object_string_add(json_vni, "originatorIp",
+                                      inet_ntoa(bgp->originator_ip));
+               json_object_string_add(
+                       json_vni, "rd",
+                       prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+       } else {
+               vty_out(vty, "%-1s %-10u %-4s %-21s",
+                       buf1, bgp->l3vni, "L3",
+                       prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+       }
+
+       for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json) {
+                       json_object_array_add(json_import_rtl,
+                                             json_object_new_string(ecom_str));
+               } else {
+                       if (listcount(bgp->vrf_import_rtl) > 1)
+                               sprintf(rt_buf, "%s, ...", ecom_str);
+                       else
+                               sprintf(rt_buf, "%s", ecom_str);
+                       vty_out(vty, " %-25s", rt_buf);
+               }
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+
+               /* If there are multiple import RTs we break here and show only
+                * one */
+               if (!json)
+                       break;
+       }
+
+       if (json)
+               json_object_object_add(json_vni, "importRTs", json_import_rtl);
+
+       for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json) {
+                       json_object_array_add(json_export_rtl,
+                                             json_object_new_string(ecom_str));
+               } else {
+                       if (listcount(bgp->vrf_export_rtl) > 1)
+                               sprintf(rt_buf, "%s, ...", ecom_str);
+                       else
+                               sprintf(rt_buf, "%s", ecom_str);
+                       vty_out(vty, " %-25s", rt_buf);
+               }
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+
+               /* If there are multiple export RTs we break here and show only
+                * one */
+               if (!json)
+                       break;
+       }
+
+       if (!json)
+               vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id));
+
+       if (json) {
+               char vni_str[VNI_STR_LEN];
+
+               json_object_object_add(json_vni, "exportRTs", json_export_rtl);
+               snprintf(vni_str, VNI_STR_LEN, "%u", bgp->l3vni);
+               json_object_object_add(json, vni_str, json_vni);
+       } else {
+               vty_out(vty, "\n");
+       }
+}
+
 static void show_vni_entry(struct hash_backet *backet, void *args[])
 {
        struct vty *vty;
@@ -600,16 +784,19 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
 
        if (json) {
                json_object_int_add(json_vni, "vni", vpn->vni);
+               json_object_string_add(json_vni, "type", "L2");
                json_object_string_add(json_vni, "inKernel",
                                       is_vni_live(vpn) ? "True" : "False");
                json_object_string_add(json_vni, "originatorIp",
                                       inet_ntoa(vpn->originator_ip));
+               json_object_string_add(json_vni, "originatorIp",
+                                      inet_ntoa(vpn->originator_ip));
                json_object_string_add(
                        json_vni, "rd",
                        prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
        } else {
-               vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
-                       inet_ntoa(vpn->originator_ip),
+               vty_out(vty, "%-1s %-10u %-4s %-21s",
+                       buf1, vpn->vni, "L2",
                        prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
        }
 
@@ -1982,7 +2169,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                                vty_out(vty,
                                        "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
                                vty_out(vty,
-                                       "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
+                                       "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
                                rd_header = 0;
                        }
 
@@ -2181,10 +2368,26 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
 static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
                          json_object *json)
 {
+       u_char found = 0;
        struct bgpevpn *vpn;
 
        vpn = bgp_evpn_lookup_vni(bgp, vni);
-       if (!vpn) {
+       if (vpn) {
+               found = 1;
+               display_vni(vty, vpn, json);
+       } else {
+               struct bgp *bgp_temp;
+               struct listnode *node = NULL;
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
+                       if (bgp_temp->l3vni == vni) {
+                               found = 1;
+                               display_l3vni(vty, bgp_temp, json);
+                       }
+               }
+       }
+
+       if (!found) {
                if (json) {
                        vty_out(vty, "{}\n");
                } else {
@@ -2192,8 +2395,6 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
                        return;
                }
        }
-
-       display_vni(vty, vpn, json);
 }
 
 /*
@@ -2202,28 +2403,29 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
 static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
                               json_object *json)
 {
-       u_int32_t num_vnis;
        void *args[2];
+       struct bgp *bgp_temp = NULL;
+       struct listnode *node;
 
-       num_vnis = hashcount(bgp->vnihash);
-       if (!num_vnis)
-               return;
 
-       if (json) {
-               json_object_int_add(json, "numVnis", num_vnis);
-       } else {
-               vty_out(vty, "Number of VNIs: %u\n", num_vnis);
+       if (!json) {
                vty_out(vty, "Flags: * - Kernel\n");
-               vty_out(vty, "  %-10s %-15s %-21s %-25s %-25s %-37s\n", "VNI",
-                       "Orig IP", "RD", "Import RT",
-                       "Export RT", "Tenant-Vrf");
+               vty_out(vty, "  %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
+                       "Type", "RD", "Import RT",
+                       "Export RT", "Tenant VRF");
        }
 
+       /* print all L2 VNIS */
        args[0] = vty;
        args[1] = json;
        hash_iterate(bgp->vnihash,
                     (void (*)(struct hash_backet *, void *))show_vni_entry,
                     args);
+
+       /* print all L3 VNIs */
+       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp))
+               show_l3vni_entry(vty, bgp_temp, json);
+
 }
 
 /*
@@ -2271,6 +2473,32 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
        return;
 }
 
+/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_set_advertise_subnet(struct bgp *bgp,
+                                     struct bgpevpn *vpn)
+{
+       if (vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 1;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
+/*
+ * evpn - disable advertisement of default g/w
+ */
+static void evpn_unset_advertise_subnet(struct bgp *bgp,
+                                       struct bgpevpn *vpn)
+{
+       if (!vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 0;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
 /*
  * EVPN (VNI advertisement) enabled. Register with zebra.
  */
@@ -2330,6 +2558,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
                if (vpn->advertise_gw_macip)
                        vty_out(vty, "   advertise-default-gw\n");
 
+               if (vpn->advertise_subnet)
+                       vty_out(vty, "   advertise-subnet\n");
+
                vty_out(vty, "  exit-vni\n");
        }
 }
@@ -2440,6 +2671,56 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_advertise_vni_subnet,
+       bgp_evpn_advertise_vni_subnet_cmd,
+       "advertise-subnet",
+       "Advertise the subnet corresponding to VNI\n")
+{
+       struct bgp *bgp_vrf = NULL;
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       if (!(advertise_type5_routes(bgp_vrf, AFI_IP) ||
+             advertise_type5_routes(bgp_vrf, AFI_IP6))) {
+               vty_out(vty,
+                       "%%Please enable ip prefix advertisement under l2vpn evpn in %s",
+                       vrf_id_to_name(bgp_vrf->vrf_id));
+               return CMD_WARNING;
+       }
+
+       evpn_set_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_vni_subnet,
+       no_bgp_evpn_advertise_vni_subnet_cmd,
+       "no advertise-subnet",
+       NO_STR
+       "Advertise All local VNIs\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       evpn_unset_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
 DEFUN (bgp_evpn_advertise_type5,
        bgp_evpn_advertise_type5_cmd,
        "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
@@ -2563,16 +2844,21 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
       "VNI number\n"
       JSON_STR)
 {
-       struct bgp *bgp;
+       struct bgp *bgp_def;
        vni_t vni;
        int idx = 0;
        u_char uj = 0;
        json_object *json = NULL;
+       u_int32_t num_l2vnis = 0;
+       u_int32_t num_l3vnis = 0;
+       uint32_t num_vnis = 0;
+       struct listnode *node = NULL;
+       struct bgp *bgp_temp = NULL;
 
        uj = use_json(argc, argv);
 
-       bgp = bgp_get_default();
-       if (!bgp)
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
                return CMD_WARNING;
 
        if (!argv_find(argv, argc, "evpn", &idx))
@@ -2582,26 +2868,36 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
                json = json_object_new_object();
 
        if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
+
+               num_l2vnis = hashcount(bgp_def->vnihash);
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
+                       if (bgp_temp->l3vni)
+                               num_l3vnis++;
+               }
+               num_vnis = num_l2vnis + num_l3vnis;
                if (uj) {
                        json_object_string_add(json, "advertiseGatewayMacip",
-                                              bgp->advertise_gw_macip
+                                              bgp_def->advertise_gw_macip
                                                       ? "Enabled"
                                                       : "Disabled");
                        json_object_string_add(json, "advertiseAllVnis",
                                               is_evpn_enabled()
                                                       ? "Enabled"
                                                       : "Disabled");
+                       json_object_int_add(json, "numVnis", num_vnis);
+                       json_object_int_add(json, "numL2Vnis", num_l2vnis);
+                       json_object_int_add(json, "numL3Vnis", num_l3vnis);
                } else {
                        vty_out(vty, "Advertise Gateway Macip: %s\n",
-                               bgp->advertise_gw_macip ? "Enabled"
+                               bgp_def->advertise_gw_macip ? "Enabled"
                                                        : "Disabled");
-
-                       /* Display all VNIs */
                        vty_out(vty, "Advertise All VNI flag: %s\n",
                                is_evpn_enabled() ? "Enabled" : "Disabled");
+                       vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
+                       vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
                }
-
-               evpn_show_all_vnis(vty, bgp, json);
+               evpn_show_all_vnis(vty, bgp_def, json);
        } else {
                int vni_idx = 0;
 
@@ -2610,7 +2906,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
 
                /* Display specific VNI */
                vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
-               evpn_show_vni(vty, bgp, vni, json);
+               evpn_show_vni(vty, bgp_def, vni, json);
        }
 
        if (uj) {
@@ -2644,7 +2940,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
  */
 DEFUN(show_bgp_l2vpn_evpn_route,
       show_bgp_l2vpn_evpn_route_cmd,
-      "show bgp l2vpn evpn route [type <macip|multicast>] [json]",
+      "show bgp l2vpn evpn route [type <macip|multicast|prefix>] [json]",
       SHOW_STR
       BGP_STR
       L2VPN_HELP_STR
@@ -2653,6 +2949,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
       "Specify Route type\n"
       "MAC-IP (Type-2) route\n"
       "Multicast (Type-3) route\n"
+      "Prefix route\n"
       JSON_STR)
 {
        struct bgp *bgp;
@@ -2677,6 +2974,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                        type = BGP_EVPN_MAC_IP_ROUTE;
                else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
                        type = BGP_EVPN_IMET_ROUTE;
+               else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+                       type = BGP_EVPN_IP_PREFIX_ROUTE;
                else
                        return CMD_WARNING;
        }
@@ -2688,7 +2987,6 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                                             json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
-
        return CMD_SUCCESS;
 }
 
@@ -2697,7 +2995,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
  */
 DEFUN(show_bgp_l2vpn_evpn_route_rd,
       show_bgp_l2vpn_evpn_route_rd_cmd,
-      "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast>] [json]",
+      "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|prefix>] [json]",
       SHOW_STR
       BGP_STR
       L2VPN_HELP_STR
@@ -2708,6 +3006,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
       "Specify Route type\n"
       "MAC-IP (Type-2) route\n"
       "Multicast (Type-3) route\n"
+      "Prefix route\n"
       JSON_STR)
 {
        struct bgp *bgp;
@@ -2745,6 +3044,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
                        type = BGP_EVPN_MAC_IP_ROUTE;
                else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
                        type = BGP_EVPN_IMET_ROUTE;
+               else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+                       type = BGP_EVPN_IP_PREFIX_ROUTE;
                else
                        return CMD_WARNING;
        }
@@ -3544,13 +3845,12 @@ static int bgp_evpn_rt_matches_existing(struct list *rtl,
 /* display L3VNI related info for a VRF instance */
 DEFUN (show_bgp_vrf_l3vni_info,
        show_bgp_vrf_l3vni_info_cmd,
-       "show bgp vrf VRFNAME l3vni info [json]",
+       "show bgp vrf VRFNAME vni [json]",
        SHOW_STR
        BGP_STR
        "show bgp vrf\n"
        "VRF Name\n"
        "L3-VNI\n"
-       "L3-VNI info\n"
        JSON_STR)
 {
        char buf[ETHER_ADDR_STRLEN];
@@ -4118,5 +4418,8 @@ void bgp_ethernetvpn_init(void)
                        &bgp_evpn_advertise_default_gw_vni_cmd);
        install_element(BGP_EVPN_VNI_NODE,
                        &no_bgp_evpn_advertise_default_gw_vni_cmd);
+       install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
+       install_element(BGP_EVPN_VNI_NODE,
+                       &no_bgp_evpn_advertise_vni_subnet_cmd);
 #endif
 }
index 60250513b678eeff506b0bb8e0a14ac48a17703b..38b39075be376b51aecdc46d1f61050b0274175e 100644 (file)
@@ -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);
                }
        }
 
index 472b9d200a4bca98930065baefb5910d4a111b24..0e2594ba8a5adf44a6363bcaed305819c3d7621b 100644 (file)
@@ -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. */
index fdc7f22ae859ed3b1d9220a47950e9ef4e3db9de..36e0c92482a832d29bc5156fd737812968d7b1a6 100644 (file)
@@ -147,7 +147,8 @@ static struct bgp_info_extra *bgp_info_extra_new(void)
 {
        struct bgp_info_extra *new;
        new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_info_extra));
-       new->label = MPLS_INVALID_LABEL;
+       new->label[0] = MPLS_INVALID_LABEL;
+       new->num_labels = 0;
        return new;
 }
 
@@ -770,9 +771,9 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new,
                /* If one path has a label but the other does not, do not treat
                 * them as equals for multipath
                 */
-               if ((new->extra &&bgp_is_valid_label(&new->extra->label))
+               if ((new->extra && bgp_is_valid_label(&new->extra->label[0]))
                    != (exist->extra
-                       && bgp_is_valid_label(&exist->extra->label))) {
+                       && bgp_is_valid_label(&exist->extra->label[0]))) {
                        if (debug)
                                zlog_debug(
                                        "%s: %s and %s cannot be multipath, one has a label while the other does not",
@@ -2225,9 +2226,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
        /* advertise/withdraw type-5 routes */
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
                if (new_select)
-                       bgp_evpn_advertise_type5_route(bgp, rn, afi, safi);
+                       bgp_evpn_advertise_type5_route(bgp, &rn->p,
+                                                      new_select->attr,
+                                                      afi, safi);
                else if (old_select)
-                       bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi);
+                       bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
        }
 
        /* Clear any route change flags. */
@@ -2670,7 +2673,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
 
 int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
               struct attr *attr, afi_t afi, safi_t safi, int type,
-              int sub_type, struct prefix_rd *prd, mpls_label_t *label,
+              int sub_type, struct prefix_rd *prd,
+              mpls_label_t *label, u_int32_t num_labels,
               int soft_reconfig, struct bgp_route_evpn *evpn)
 {
        int ret;
@@ -2681,9 +2685,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
        struct attr *attr_new;
        struct bgp_info *ri;
        struct bgp_info *new;
+       struct bgp_info_extra *extra;
        const char *reason;
        char pfx_buf[BGP_PRD_PATH_STRLEN];
-       char label_buf[20];
        int connected = 0;
        int do_loop_check = 1;
        int has_valid_label = 0;
@@ -2698,10 +2702,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        bgp = peer->bgp;
        rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
-       has_valid_label = bgp_is_valid_label(label);
-
-       if (has_valid_label)
-               sprintf(label_buf, "label %u", label_pton(label));
+       /* TODO: Check to see if we can get rid of "is_valid_label" */
+       if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+               has_valid_label = (num_labels > 0) ? 1 : 0;
+       else
+               has_valid_label = bgp_is_valid_label(label);
 
        /* When peer's soft reconfiguration enabled.  Record input packet in
           Adj-RIBs-In.  */
@@ -2821,7 +2826,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                    && attrhash_cmp(ri->attr, attr_new)
                    && (!has_valid_label
                        || memcmp(&(bgp_info_extra_get(ri))->label, label,
-                                 BGP_LABEL_BYTES)
+                                 num_labels * sizeof(mpls_label_t))
                                   == 0)
                    && (overlay_index_equal(
                               afi, ri, evpn == NULL ? NULL : &evpn->eth_s_id,
@@ -2832,7 +2837,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                            && CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) {
                                if (bgp_debug_update(peer, p, NULL, 1)) {
                                        bgp_debug_rdpfxpath2str(
-                                               afi, safi, prd, p, label,
+                                               afi, safi, prd, p,
+                                               label, num_labels,
                                                addpath_id ? 1 : 0, addpath_id,
                                                pfx_buf, sizeof(pfx_buf));
                                        zlog_debug("%s rcvd %s", peer->host,
@@ -2857,7 +2863,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                                        }
 
                                        bgp_debug_rdpfxpath2str(
-                                               afi, safi, prd, p, label,
+                                               afi, safi, prd, p,
+                                               label, num_labels,
                                                addpath_id ? 1 : 0, addpath_id,
                                                pfx_buf, sizeof(pfx_buf));
                                        zlog_debug(
@@ -2883,7 +2890,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
-                                       afi, safi, prd, p, label,
+                                       afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                                zlog_debug(
@@ -2896,7 +2904,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
                /* Received Logging. */
                if (bgp_debug_update(peer, p, NULL, 1)) {
-                       bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+                       bgp_debug_rdpfxpath2str(afi, safi, prd, p,
+                                               label, num_labels,
                                                addpath_id ? 1 : 0, addpath_id,
                                                pfx_buf, sizeof(pfx_buf));
                        zlog_debug("%s rcvd %s", peer->host, pfx_buf);
@@ -2987,9 +2996,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
                /* Update MPLS label */
                if (has_valid_label) {
-                       memcpy(&(bgp_info_extra_get(ri))->label, label,
-                              BGP_LABEL_BYTES);
-                       bgp_set_valid_label(&(bgp_info_extra_get(ri))->label);
+                       extra = bgp_info_extra_get(ri);
+                       memcpy(&extra->label, label,
+                              num_labels * sizeof(mpls_label_t));
+                       extra->num_labels = num_labels;
+                       if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
+                               bgp_set_valid_label(&extra->label[0]);
                }
 
 #if ENABLE_BGP_VNC
@@ -3126,7 +3138,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                        peer->rcvd_attr_printed = 1;
                }
 
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd %s", peer->host, pfx_buf);
@@ -3137,9 +3150,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        /* Update MPLS label */
        if (has_valid_label) {
-               memcpy(&(bgp_info_extra_get(new))->label, label,
-                      BGP_LABEL_BYTES);
-               bgp_set_valid_label(&(bgp_info_extra_get(new))->label);
+               extra = bgp_info_extra_get(new);
+               memcpy(&extra->label, label,
+                      num_labels * sizeof(mpls_label_t));
+               extra->num_labels = num_labels;
+               if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
+                       bgp_set_valid_label(&extra->label[0]);
        }
 
        /* Update Overlay Index */
@@ -3241,7 +3257,8 @@ filtered:
                        peer->rcvd_attr_printed = 1;
                }
 
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s",
@@ -3276,7 +3293,8 @@ filtered:
 
 int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                 struct attr *attr, afi_t afi, safi_t safi, int type,
-                int sub_type, struct prefix_rd *prd, mpls_label_t *label,
+                int sub_type, struct prefix_rd *prd,
+                mpls_label_t *label, u_int32_t num_labels,
                 struct bgp_route_evpn *evpn)
 {
        struct bgp *bgp;
@@ -3312,7 +3330,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                if (!bgp_adj_in_unset(rn, peer, addpath_id)) {
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
-                                       afi, safi, prd, p, label,
+                                       afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                                zlog_debug(
@@ -3332,7 +3351,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        /* Logging. */
        if (bgp_debug_update(peer, p, NULL, 1)) {
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host,
@@ -3343,7 +3363,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
        if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY))
                bgp_rib_withdraw(rn, ri, peer, afi, safi, prd);
        else if (bgp_debug_update(peer, p, NULL, 1)) {
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p,
+                                       label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s Can't find the route %s", peer->host, pfx_buf);
@@ -3469,14 +3490,18 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                                continue;
 
                        struct bgp_info *ri = rn->info;
-                       mpls_label_t label = (ri && ri->extra)
-                                                    ? ri->extra->label
-                                                    : MPLS_INVALID_LABEL;
+                       u_int32_t num_labels = 0;
+                       mpls_label_t *label_pnt = NULL;
+
+                       if (ri && ri->extra)
+                               num_labels = ri->extra->num_labels;
+                       if (num_labels)
+                               label_pnt = &ri->extra->label[0];
 
                        ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
                                         ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
-                                        BGP_ROUTE_NORMAL, prd, &label, 1,
-                                        NULL);
+                                        BGP_ROUTE_NORMAL, prd,
+                                        label_pnt, num_labels, 1, NULL);
 
                        if (ret < 0) {
                                bgp_unlock_node(rn);
@@ -4029,11 +4054,12 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                if (attr)
                        ret = bgp_update(peer, &p, addpath_id, attr, afi, safi,
                                         ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                        NULL, NULL, 0, NULL);
+                                        NULL, NULL, 0, 0, NULL);
                else
                        ret = bgp_withdraw(peer, &p, addpath_id, attr, afi,
                                           safi, ZEBRA_ROUTE_BGP,
-                                          BGP_ROUTE_NORMAL, NULL, NULL, NULL);
+                                          BGP_ROUTE_NORMAL, NULL,
+                                          NULL, 0, NULL);
 
                /* Address family configuration mismatch or maximum-prefix count
                   overflow. */
@@ -4345,10 +4371,13 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
 #if ENABLE_BGP_VNC
        mpls_label_t label = 0;
 #endif
+       u_int32_t num_labels = 0;
        union gw_addr add;
 
        assert(bgp_static);
 
+       if (bgp_static->label != MPLS_INVALID_LABEL)
+               num_labels = 1;
        rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p,
                              &bgp_static->prd);
 
@@ -4443,7 +4472,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
                        ri->uptime = bgp_clock();
 #if ENABLE_BGP_VNC
                        if (ri->extra)
-                               label = decode_label(&ri->extra->label);
+                               label = decode_label(&ri->extra->label[0]);
 #endif
 
                        /* Process change. */
@@ -4466,7 +4495,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
                        attr_new, rn);
        SET_FLAG(new->flags, BGP_INFO_VALID);
        new->extra = bgp_info_extra_new();
-       new->extra->label = bgp_static->label;
+       if (num_labels) {
+               new->extra->label[0] = bgp_static->label;
+               new->extra->num_labels = num_labels;
+       }
 #if ENABLE_BGP_VNC
        label = decode_label(&bgp_static->label);
 #endif
@@ -6713,7 +6745,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
                }
        }
 
-       label = decode_label(&binfo->extra->label);
+       label = decode_label(&binfo->extra->label[0]);
 
        if (bgp_is_valid_label(&label)) {
                if (json) {
@@ -7051,14 +7083,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
 #if defined(HAVE_CUMULUS)
        if (!json_paths && safi == SAFI_EVPN) {
-               char tag_buf[20];
+               char tag_buf[30];
 
                bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2));
                vty_out(vty, "  Route %s", buf2);
                tag_buf[0] = '\0';
-               if (binfo->extra) {
-                       bgp_evpn_label2str(&binfo->extra->label, tag_buf,
-                                          sizeof(tag_buf));
+               if (binfo->extra && binfo->extra->num_labels) {
+                       bgp_evpn_label2str(binfo->extra->label,
+                                          binfo->extra->num_labels,
+                                          tag_buf, sizeof(tag_buf));
                        vty_out(vty, " VNI %s", tag_buf);
                }
                vty_out(vty, "\n");
@@ -7692,13 +7725,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
 /* Remote Label */
 #if defined(HAVE_CUMULUS)
-               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)
+               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])
                    && safi != SAFI_EVPN)
 #else
-               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label))
+               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]))
 #endif
                {
-                       mpls_label_t label = label_pton(&binfo->extra->label);
+                       mpls_label_t label = label_pton(
+                                               &binfo->extra->label[0]);
                        if (json_paths)
                                json_object_int_add(json_path, "remoteLabel",
                                                    label);
index fc15720ebc9a821799a833aa0c77a192268cb699..2d4034d77dcbfa178439f36ef7549077934279f7 100644 (file)
@@ -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 */
index 8c9f9f65ca4e4b3894e6d27ae7d2435b41ecaca1..de2410e009f00475d2403c9097b1496faaa5f5a8 100644 (file)
@@ -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;
        }
 
index b63dfbed0ac240cacdcb6277ff13be46527f3fd5..9fa733a720e993108972fe2d9a2ad8596492d1d3 100644 (file)
@@ -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 */
index d30b057cbc298fe9a44a71c0fcc20d8ccde7baef..4a8eeb9121447b54fafd3cb465224038fed0388c 100644 (file)
@@ -6126,8 +6126,10 @@ DEFUN_NOSH (address_family_ipv4_safi,
                VTY_DECLVAR_CONTEXT(bgp, bgp);
                safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
                if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
-                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
-                       vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
+                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+                   && safi != SAFI_EVPN) {
+                       vty_out(vty,
+                               "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
                vty->node = bgp_node_type(AFI_IP, safi);
@@ -6148,8 +6150,10 @@ DEFUN_NOSH (address_family_ipv6_safi,
                VTY_DECLVAR_CONTEXT(bgp, bgp);
                safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
                if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
-                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
-                       vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
+                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+                   && safi != SAFI_EVPN) {
+                       vty_out(vty,
+                               "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
                vty->node = bgp_node_type(AFI_IP6, safi);
@@ -6191,10 +6195,6 @@ DEFUN_NOSH (address_family_evpn,
        "Address Family modifier\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
-               vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
        vty->node = BGP_EVPN_NODE;
        return CMD_SUCCESS;
 }
index 7f7d746256cbe0c8ba6fdd23598bd3cea0c13db2..e0bd74a206992bb38cea75048e43a09f19eb3a2c 100644 (file)
@@ -1142,10 +1142,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
                }
 
-               if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label)
+               if (mpinfo->extra &&
+                   bgp_is_valid_label(&mpinfo->extra->label[0])
                    && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                        has_valid_label = 1;
-                       label = label_pton(&mpinfo->extra->label);
+                       label = label_pton(&mpinfo->extra->label[0]);
 
                        api_nh->label_num = 1;
                        api_nh->labels[0] = label;
@@ -1634,6 +1635,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
        zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
 }
 
+int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni)
+{
+       struct stream *s = NULL;
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return 0;
+
+       /* Don't try to register if Zebra doesn't know of this instance. */
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+               return 0;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_ADVERTISE_SUBNET, bgp->vrf_id);
+       stream_putc(s, advertise);
+       stream_put3(s, vni);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
 {
        struct stream *s = NULL;
@@ -1820,6 +1844,55 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
 }
 
+static void bgp_zebra_process_local_ip_prefix(int cmd,
+                                             struct zclient *zclient,
+                                             zebra_size_t length,
+                                             vrf_id_t vrf_id)
+{
+       struct stream *s = NULL;
+       struct bgp *bgp_vrf = NULL;
+       struct prefix p;
+       char buf[PREFIX_STRLEN];
+
+       memset(&p, 0, sizeof(struct prefix));
+       s = zclient->ibuf;
+       stream_get(&p, s, sizeof(struct prefix));
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp_vrf)
+               return;
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("Recv prefix %s %s on vrf %s",
+                          prefix2str(&p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) {
+
+               if (p.family == AF_INET)
+                       return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
+                                                             NULL,
+                                                             AFI_IP,
+                                                             SAFI_UNICAST);
+               else
+                       return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
+                                                             NULL,
+                                                             AFI_IP6,
+                                                             SAFI_UNICAST);
+
+       } else {
+               if (p.family == AF_INET)
+                       return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
+                                                            AFI_IP,
+                                                            SAFI_UNICAST);
+               else
+                       return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
+                                                            AFI_IP6,
+                                                            SAFI_UNICAST);
+       }
+}
+
 extern struct zebra_privs_t bgpd_privs;
 
 void bgp_zebra_init(struct thread_master *master)
@@ -1852,6 +1925,8 @@ void bgp_zebra_init(struct thread_master *master)
        zclient->local_macip_del = bgp_zebra_process_local_macip;
        zclient->local_l3vni_add = bgp_zebra_process_local_l3vni;
        zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
+       zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
+       zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
 }
 
 void bgp_zebra_destroy(void)
index 7d37864f44a8cce16d32064a8dfbc77cadf002fc..da5160bc16d6c0ce96e8950eb58dff71ebe5a257 100644 (file)
@@ -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);
 
index 95666143a5c5a9723e70f789d59e52193f8c0487..9d169eed32c571e1f6aaaef43df8b44270c657cd 100644 (file)
@@ -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 */
 
index 8727c5d5ea5c20a1bb1eae186387df7ffd2935af..e1508dbd83bd0e858f7d50b7bf0ccc7366b407ca 100644 (file)
@@ -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 */
index bd79518bfd75c7caa2d4d19d39508faf8ddaed49..271c74851018c9bb34b0592e5db57f61639450cd 100644 (file)
@@ -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 */
index 15d27b396160dc4f4e204c7cd4bebfa895a3dbd1..28d068cc578453ed273c3a8a1cdb0b31b1f2ed1d 100644 (file)
@@ -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)
index d4921ce40a80ec6d49c05a81313a1c664544bc83..e88dd9399c565b01d6711e5c9222827b51fd89de 100644 (file)
@@ -317,7 +317,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn,
                   iattr,          /* bgp_update copies this attr */
                   afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                   BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
-                  NULL,                         /* tag not used for unicast */
+                  NULL, 0,                      /* tag not used for unicast */
                   0, NULL);                     /* EVPN not used */
        bgp_attr_unintern(&iattr);
 }
@@ -398,7 +398,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct route_node *rn,
                     NULL,                /* attr, ignored */
                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                     BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
-                    NULL, NULL); /* tag not used for unicast */
+                    NULL, 0, NULL); /* tag not used for unicast */
 }
 
 static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
@@ -498,7 +498,7 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
                                        ZEBRA_ROUTE_VNC_DIRECT,
                                        BGP_ROUTE_REDISTRIBUTE,
                                        NULL, /* RD not used for unicast */
-                                       NULL,
+                                       NULL, 0,
                                        NULL); /* tag not used for unicast */
                        }
                }
@@ -880,7 +880,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
                                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                                     BGP_ROUTE_REDISTRIBUTE,
                                     NULL,      /* RD not used for unicast */
-                                    NULL, NULL); /* tag not used for unicast */
+                                    NULL, 0, NULL); /* tag not used for unicast */
                        /*
                         * yuck!
                         *  - but consistent with rest of function
@@ -909,7 +909,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
                                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                                     BGP_ROUTE_REDISTRIBUTE,
                                     NULL,      /* RD not used for unicast */
-                                    NULL, NULL); /* tag not used for unicast */
+                                    NULL, 0, NULL); /* tag not used for unicast */
                }
        }
 }
@@ -1048,7 +1048,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
                                                                unicast */
                                                   NULL,     /* tag not used for
                                                                unicast */
-                                                  0, NULL); /* EVPN not used */
+                                                  0, 0, NULL); /* EVPN not used */
 
                                        bgp_attr_unintern(&iattr);
                                }
@@ -1142,7 +1142,7 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
                                                     BGP_ROUTE_REDISTRIBUTE,
                                                     NULL, /* RD not used for
                                                              unicast */
-                                                    NULL, NULL); /* tag not
+                                                    NULL, 0, NULL); /* tag not
                                                                     used for
                                                                     unicast */
                                }
@@ -1260,7 +1260,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
                   BGP_ROUTE_REDISTRIBUTE,
                   NULL, /* RD not used for unicast */
                   NULL, /* tag not used for unicast */
-                  0, NULL); /* EVPN not used */
+                  0, 0, NULL); /* EVPN not used */
 
        bgp_attr_unintern(&iattr);
 
@@ -1374,7 +1374,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
                     ZEBRA_ROUTE_VNC_DIRECT,
                     BGP_ROUTE_REDISTRIBUTE,
                     NULL, /* RD not used for unicast */
-                    NULL,
+                    NULL, 0,
                     NULL); /* tag not used for unicast */
        return;
 }
@@ -1496,7 +1496,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct route_table *rt,
                                                     BGP_ROUTE_REDISTRIBUTE,
                                                     NULL, /* RD not used for
                                                              unicast */
-                                                    NULL, NULL); /* tag not
+                                                    NULL, 0, NULL); /* tag not
                                                                     used for
                                                                     unicast,
                                                                     EVPN
@@ -1719,7 +1719,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
                   afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
                   BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
                   NULL,     /* tag not used for unicast, EVPN neither */
-                  0, NULL); /* EVPN not used */
+                  0, 0, NULL); /* EVPN not used */
        bgp_attr_unintern(&iattr);
 }
 
@@ -1734,7 +1734,7 @@ static int vncExportWithdrawTimer(struct thread *t)
                     NULL,                        /* attr, ignored */
                     family2afi(eti->node->p.family), SAFI_UNICAST, eti->type,
                     eti->subtype, NULL, /* RD not used for unicast */
-                    NULL, NULL); /* tag not used for unicast, EVPN neither */
+                    NULL, 0, NULL); /* tag not used for unicast, EVPN neither */
 
        /*
         * Free the eti
@@ -1965,7 +1965,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
                                                   NULL,     /* tag not used for
                                                                unicast, EVPN
                                                                neither */
-                                                  0, NULL); /* EVPN not used */
+                                                  0, 0, NULL); /* EVPN not used */
                                        bgp_attr_unintern(&iattr);
                                }
                        }
@@ -2026,7 +2026,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
                                             ZEBRA_ROUTE_VNC_DIRECT_RH,
                                             BGP_ROUTE_REDISTRIBUTE,
                                             NULL, /* RD not used for unicast */
-                                            NULL, NULL); /* tag not used for
+                                            NULL, 0, NULL); /* tag not used for
                                                             unicast, EVPN
                                                             neither */
                        }
index f7e86123b4f3422a5e4f372b9e9d30a6c2240c94..cfa4c599f2a1a44c4470fe163d9ae30c11949b7c 100644 (file)
@@ -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;
 
index bf65ac7c7da4dbd7bc04b02dfe47b9c0457d15a5..66be533e84d17d2babf5a1913614e9fe70dfcada 100644 (file)
--- 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),
index 2fa3a9c0ef512eb67496f20c28172031c6f48584..2e15fa2f5c2c0c884b99cd6f2fdc0b68d3e1ab79 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -141,7 +141,9 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
        return vrf;
 }
 
-/* Delete a VRF. This is called in vrf_terminate(). */
+/* Delete a VRF. This is called when the underlying VRF goes away, a
+ * pre-configured VRF is deleted or when shutting down (vrf_terminate()).
+ */
 void vrf_delete(struct vrf *vrf)
 {
        if (debug_vrf)
@@ -150,6 +152,23 @@ void vrf_delete(struct vrf *vrf)
        if (vrf_is_enabled(vrf))
                vrf_disable(vrf);
 
+       /* If the VRF is user configured, it'll stick around, just remove
+        * the ID mapping. Interfaces assigned to this VRF should've been
+        * removed already as part of the VRF going down.
+        */
+       if (vrf_is_user_cfged(vrf)) {
+               if (vrf->vrf_id != VRF_UNKNOWN) {
+                       /* Delete any VRF interfaces - should be only
+                        * the VRF itself, other interfaces should've
+                        * been moved out of the VRF.
+                        */
+                       if_terminate(vrf);
+                       RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
+                       vrf->vrf_id = VRF_UNKNOWN;
+               }
+               return;
+       }
+
        if (vrf_master.vrf_delete_hook)
                (*vrf_master.vrf_delete_hook)(vrf);
 
@@ -172,14 +191,6 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id)
        return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf));
 }
 
-/*
- * Check whether the VRF is enabled.
- */
-static int vrf_is_enabled(struct vrf *vrf)
-{
-       return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
-}
-
 /*
  * Enable a VRF - that is, let the VRF be ready to use.
  * The VRF_ENABLE_HOOK callback will be called to inform
@@ -408,10 +419,16 @@ void vrf_terminate(void)
                zlog_debug("%s: Shutting down vrf subsystem",
                           __PRETTY_FUNCTION__);
 
-       while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL)
+       while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) {
+               /* Clear configured flag and invoke delete. */
+               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
                vrf_delete(vrf);
-       while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL)
+       }
+       while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) {
+               /* Clear configured flag and invoke delete. */
+               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
                vrf_delete(vrf);
+       }
 }
 
 /* Create a socket for the VRF. */
@@ -473,6 +490,8 @@ DEFUN_NOSH (no_vrf,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       /* Clear configured flag and invoke delete. */
+       UNSET_FLAG(vrfp->status, VRF_CONFIGURED);
        vrf_delete(vrfp);
 
        return CMD_SUCCESS;
index 7e625769e7f332c447b6e84387ec7c3c42a3ffd7..99c048c7025361987d7ab700fb05d0a2dff2b740 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -75,7 +75,8 @@ struct vrf {
 
        /* Zebra internal VRF status */
        u_char status;
-#define VRF_ACTIVE     (1 << 0)
+#define VRF_ACTIVE     (1 << 0) /* VRF is up in kernel */
+#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */
 
        /* Interfaces belonging to this VRF */
        struct if_name_head ifaces_by_name;
@@ -119,6 +120,32 @@ extern vrf_id_t vrf_name_to_id(const char *);
                (V) = vrf->vrf_id;                                             \
        } while (0)
 
+/*
+ * Check whether the VRF is enabled.
+ */
+static inline int vrf_is_enabled(struct vrf *vrf)
+{
+       return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
+}
+
+/* check if the vrf is user configured */
+static inline int vrf_is_user_cfged(struct vrf *vrf)
+{
+       return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
+/* Mark that VRF has user configuration */
+static inline void vrf_set_user_cfged(struct vrf *vrf)
+{
+       SET_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
+/* Mark that VRF no longer has any user configuration */
+static inline void vrf_reset_user_cfged(struct vrf *vrf)
+{
+       UNSET_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
 /*
  * Utilities to obtain the user data
  */
index 6f770c66e412577f6496895820f0c47d8ff7e4f9..0c29b523bf7ad7edb6a444bf32e021972420ff6f 100644 (file)
@@ -2333,6 +2333,16 @@ static int zclient_read(struct thread *thread)
                        (*zclient->local_macip_del)(command, zclient, length,
                                                    vrf_id);
                break;
+       case ZEBRA_IP_PREFIX_ROUTE_ADD:
+               if (zclient->local_ip_prefix_add)
+                       (*zclient->local_ip_prefix_add)(command, zclient,
+                                                       length, vrf_id);
+               break;
+       case ZEBRA_IP_PREFIX_ROUTE_DEL:
+               if (zclient->local_ip_prefix_del)
+                       (*zclient->local_ip_prefix_del)(command, zclient,
+                                                       length, vrf_id);
+               break;
        case ZEBRA_PW_STATUS_UPDATE:
                if (zclient->pw_status_update)
                        (*zclient->pw_status_update)(command, zclient, length,
index bd4d32d2bd3818b1dd75c772321a82b315142fb9..5c7c5d6d5b0ca079ac76be6e5b4e96bb0800f411 100644 (file)
@@ -109,6 +109,7 @@ typedef enum {
        ZEBRA_FEC_UNREGISTER,
        ZEBRA_FEC_UPDATE,
        ZEBRA_ADVERTISE_DEFAULT_GW,
+       ZEBRA_ADVERTISE_SUBNET,
        ZEBRA_ADVERTISE_ALL_VNI,
        ZEBRA_VNI_ADD,
        ZEBRA_VNI_DEL,
@@ -118,6 +119,8 @@ typedef enum {
        ZEBRA_REMOTE_VTEP_DEL,
        ZEBRA_MACIP_ADD,
        ZEBRA_MACIP_DEL,
+       ZEBRA_IP_PREFIX_ROUTE_ADD,
+       ZEBRA_IP_PREFIX_ROUTE_DEL,
        ZEBRA_REMOTE_MACIP_ADD,
        ZEBRA_REMOTE_MACIP_DEL,
        ZEBRA_PW_ADD,
@@ -204,6 +207,8 @@ struct zclient {
        int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
+       void (*local_ip_prefix_add)(int, struct zclient *, uint16_t, vrf_id_t);
+       void (*local_ip_prefix_del)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t);
@@ -343,8 +348,8 @@ enum zapi_route_notify_owner {
 };
 
 /* Zebra MAC types */
-#define ZEBRA_MAC_TYPE_STICKY                0x01 /* Sticky MAC*/
-#define ZEBRA_MAC_TYPE_GW                    0x02 /* gateway (SVI) mac*/
+#define ZEBRA_MACIP_TYPE_STICKY                0x01 /* Sticky MAC*/
+#define ZEBRA_MACIP_TYPE_GW                    0x02 /* gateway (SVI) mac*/
 
 struct zclient_options {
        bool receive_notify;
index 138a4463212d684b91b44ebad3bc2c520caf363b..967f855fbc45fff1c96df49aea448196457a721f 100644 (file)
@@ -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;
 
index 61051ba87e966148983c57c4b4305c299bd9f361..22c81b57841320a20476be61c55ec979590b4920 100644 (file)
@@ -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.
index 9d8ca34f82cbaa4e54d3b9a198994a14eef71bc8..27a49716913b41a0d4b95fce0260a88a27f10748 100644 (file)
@@ -384,6 +384,13 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
  */
 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf);
 
+/*
+ * Called when VRF becomes inactive, cleans up information but keeps
+ * the table itself.
+ * NOTE: Currently supported only for default VRF.
+ */
+void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf);
+
 /*
  * Called upon process exiting, need to delete LSP forwarding
  * entries from the kernel.
index b3b9c6d18a4c9f1144d2c75ad86127def4129f22..c48a6f7bd8ad377e8b7e882281a5f0f8cc147ea1 100644 (file)
@@ -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;
index 246a7e7e4c597ce5ab315e102ae3c13da39d1a8b..b9b3048486f7132b94d5dade28790c2a3624c77c 100644 (file)
 
 extern struct zebra_t zebrad;
 
+static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
+                                  safi_t safi);
+static void zebra_rnhtable_node_cleanup(struct route_table *table,
+                                       struct route_node *node);
+
 /* VRF information update. */
 static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
 {
@@ -82,7 +87,7 @@ static int zebra_vrf_new(struct vrf *vrf)
        struct zebra_vrf *zvrf;
 
        if (IS_ZEBRA_DEBUG_EVENT)
-               zlog_info("ZVRF %s with id %u", vrf->name, vrf->vrf_id);
+               zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id);
 
        zvrf = zebra_vrf_alloc();
        zvrf->zns = zebra_ns_lookup(
@@ -101,14 +106,36 @@ static int zebra_vrf_enable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
        struct interface *ifp;
        afi_t afi;
        safi_t safi;
 
        assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now active",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Inform clients that the VRF is now active. This is an
+        * add for the clients.
+        */
        zebra_vrf_add_update(zvrf);
 
+       /* Allocate tables */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       zebra_vrf_table_create(zvrf, afi, safi);
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->rnh_table[afi] = table;
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->import_check_table[afi] = table;
+       }
+
+       /* Install any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -132,6 +159,9 @@ static int zebra_vrf_enable(struct vrf *vrf)
                                }
                }
 
+       /* Kick off any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_enable(zvrf);
+
        return 0;
 }
 
@@ -142,13 +172,19 @@ static int zebra_vrf_disable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
+       struct interface *ifp;
+       u_int32_t table_id;
        afi_t afi;
        safi_t safi;
+       unsigned i;
 
-       if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("VRF %s id %u is now disabled.", zvrf_name(zvrf),
-                          zvrf_id(zvrf));
+       assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now inactive",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Uninstall any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -161,6 +197,84 @@ static int zebra_vrf_disable(struct vrf *vrf)
                                                afi, safi, &rn->p, NULL, si);
                }
 
+       /* Stop any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_disable(zvrf);
+
+       /* Inform clients that the VRF is now inactive. This is a
+        * delete for the clients.
+        */
+       zebra_vrf_delete_update(zvrf);
+
+       /* If asked to retain routes, there's nothing more to do. */
+       if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
+               return 0;
+
+       /* Remove all routes. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       rib_close_table(zvrf->table[afi][safi]);
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id])
+                                       rib_close_table(zvrf->other_table[afi][table_id]);
+       }
+
+       /* Cleanup Vxlan, MPLS and PW tables. */
+       zebra_vxlan_cleanup_tables(zvrf);
+       zebra_mpls_cleanup_tables(zvrf);
+       zebra_pw_exit(zvrf);
+
+       /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */
+       FOR_ALL_INTERFACES (vrf, ifp)
+               if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
+
+       /* clean-up work queues */
+       for (i = 0; i < MQ_SIZE; i++) {
+               struct listnode *lnode, *nnode;
+               struct route_node *rnode;
+               rib_dest_t *dest;
+
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
+                       dest = rib_dest_from_rnode(rnode);
+                       if (dest && rib_dest_vrf(dest) == zvrf) {
+                               route_unlock_node(rnode);
+                               list_delete_node(zebrad.mq->subq[i], lnode);
+                               zebrad.mq->size--;
+                       }
+               }
+       }
+
+       /* Cleanup (free) routing tables and NHT tables. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               void *table_info;
+
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+                       table = zvrf->table[afi][safi];
+                       table_info = table->info;
+                       route_table_finish(table);
+                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       zvrf->table[afi][safi] = NULL;
+               }
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id]) {
+                                       table = zvrf->other_table[afi][table_id];
+                                       table_info = table->info;
+                                       route_table_finish(table);
+                                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                                       zvrf->other_table[afi][table_id] = NULL;
+                               }
+
+               route_table_finish(zvrf->rnh_table[afi]);
+               zvrf->rnh_table[afi] = NULL;
+               route_table_finish(zvrf->import_check_table[afi]);
+               zvrf->import_check_table[afi] = NULL;
+       }
+
        return 0;
 }
 
@@ -174,38 +288,9 @@ static int zebra_vrf_delete(struct vrf *vrf)
        unsigned i;
 
        assert(zvrf);
-
-       zebra_vrf_delete_update(zvrf);
-
-       /* uninstall everything */
-       if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) {
-               struct interface *ifp;
-
-               for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
-                       for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST;
-                            safi++)
-                               rib_close_table(zvrf->table[afi][safi]);
-
-                       if (vrf->vrf_id == VRF_DEFAULT)
-                               for (table_id = 0;
-                                    table_id < ZEBRA_KERNEL_TABLE_MAX;
-                                    table_id++)
-                                       if (zvrf->other_table[afi][table_id])
-                                               rib_close_table(
-                                                       zvrf->other_table
-                                                               [afi]
-                                                               [table_id]);
-               }
-
-               /* Cleanup Vxlan table and update kernel */
-               zebra_vxlan_close_tables(zvrf);
-
-               zebra_mpls_close_tables(zvrf);
-               zebra_pw_exit(zvrf);
-
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
-       }
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u deleted",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
        /* clean-up work queues */
        for (i = 0; i < MQ_SIZE; i++) {
@@ -213,8 +298,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                struct route_node *rnode;
                rib_dest_t *dest;
 
-               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
-                                      rnode)) {
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
                        dest = rib_dest_from_rnode(rnode);
                        if (dest && rib_dest_vrf(dest) == zvrf) {
                                route_unlock_node(rnode);
@@ -224,22 +308,27 @@ static int zebra_vrf_delete(struct vrf *vrf)
                }
        }
 
+       /* Free Vxlan and MPLS. */
+       zebra_vxlan_close_tables(zvrf);
+       zebra_mpls_close_tables(zvrf);
+
        /* release allocated memory */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                void *table_info;
 
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
                        table = zvrf->table[afi][safi];
-                       table_info = table->info;
-                       route_table_finish(table);
-                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       if (table) {
+                               table_info = table->info;
+                               route_table_finish(table);
+                               XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       }
 
                        table = zvrf->stable[afi][safi];
                        route_table_finish(table);
                }
 
-               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
-                    table_id++)
+               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++)
                        if (zvrf->other_table[afi][table_id]) {
                                table = zvrf->other_table[afi][table_id];
                                table_info = table->info;
@@ -251,7 +340,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                route_table_finish(zvrf->import_check_table[afi]);
        }
 
-       /* cleanup evpn states for vrf */
+       /* Cleanup EVPN states for vrf */
        zebra_vxlan_vrf_delete(zvrf);
 
        list_delete_all_node(zvrf->rid_all_sorted_list);
@@ -262,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf)
        return 0;
 }
 
+/* Return if this VRF has any FRR configuration or not.
+ * IMPORTANT: This function needs to be updated when additional configuration
+ * is added for a VRF.
+ */
+int zebra_vrf_has_config(struct zebra_vrf *zvrf)
+{
+       afi_t afi;
+       safi_t safi;
+       struct route_table *stable;
+
+       /* NOTE: This is a don't care for the default VRF, but we go through
+        * the motions to keep things consistent.
+        */
+       /* Any static routes? */
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+                       stable = zvrf->stable[afi][safi];
+                       if (!stable)
+                               continue;
+                       if (route_table_count(stable))
+                               return 1;
+               }
+       }
+
+       /* EVPN L3-VNI? */
+       if (zvrf->l3vni)
+               return 1;
+
+       return 0;
+}
+
 /* Lookup the routing table in a VRF based on both VRF-Id and table-id.
  * NOTE: Table-id is relevant only in the Default VRF.
  */
@@ -354,9 +474,9 @@ struct zebra_vrf *zebra_vrf_alloc(void)
 
        zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
 
+       /* Allocate table for static route configuration. */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
-                       zebra_vrf_table_create(zvrf, afi, safi);
                        if (afi == AFI_IP6)
                                table = srcdest_table_init();
                        else
@@ -364,14 +484,6 @@ struct zebra_vrf *zebra_vrf_alloc(void)
                        table->cleanup = zebra_stable_node_cleanup;
                        zvrf->stable[afi][safi] = table;
                }
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->rnh_table[afi] = table;
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->import_check_table[afi] = table;
        }
 
        zebra_vxlan_init_tables(zvrf);
@@ -477,16 +589,23 @@ static int vrf_config_write(struct vty *vty)
                if (!zvrf)
                        continue;
 
-               if (vrf->vrf_id != VRF_DEFAULT)
+               if (zvrf_id(zvrf) == VRF_DEFAULT) {
+                       if (zvrf->l3vni)
+                               vty_out(vty, "vni %u\n", zvrf->l3vni);
+                       vty_out(vty, "!\n");
+               }
+
+               if (vrf_is_user_cfged(vrf)) {
                        vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
+                       if (zvrf->l3vni)
+                               vty_out(vty, " vni %u\n", zvrf->l3vni);
+                       vty_out(vty, "!\n");
+               }
 
                static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
                static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute");
                static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route");
 
-               if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni)
-                       vty_out(vty, " vni %u\n", zvrf->l3vni);
-
                if (vrf->vrf_id != VRF_DEFAULT)
                        vty_out(vty, "!\n");
        }
index c7a0717ee8291bc655f3bfff7e1f23d3ade2e00c..fe7e77e8bee7c47bceb785c26888fd812f888b0f 100644 (file)
@@ -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
index 62869b7eec9b59831c84ca9b1900066c8379b494..f8c9833854926a7152bd97395a34f6511e9bc989 100644 (file)
@@ -231,13 +231,19 @@ static int zebra_static_route_leak(struct vty *vty,
                        type = STATIC_IPV6_GATEWAY;
        }
 
-       if (!negate)
+       if (!negate) {
                static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
                                 bh_type, tag, distance, zvrf, nh_zvrf,
                                 &snh_label);
-       else
+               /* Mark as having FRR configuration */
+               vrf_set_user_cfged(zvrf->vrf);
+       } else {
                static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
                                    tag, distance, zvrf, &snh_label);
+               /* If no other FRR config for this VRF, mark accordingly. */
+               if (!zebra_vrf_has_config(zvrf))
+                       vrf_reset_user_cfged(zvrf->vrf);
+       }
 
        return CMD_SUCCESS;
 }
@@ -247,19 +253,39 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
                              const char *mask_str, const char *src_str,
                              const char *gate_str, const char *ifname,
                              const char *flag_str, const char *tag_str,
-                             const char *distance_str, const char *vrf_id_str,
+                             const char *distance_str, const char *vrf_name,
                              const char *label_str)
 {
        struct zebra_vrf *zvrf;
+       struct vrf *vrf;
 
        /* VRF id */
-       zvrf = zebra_vrf_lookup_by_name(vrf_id_str);
+       zvrf = zebra_vrf_lookup_by_name(vrf_name);
 
-       if (!zvrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str);
+       /* When trying to delete, the VRF must exist. */
+       if (negate && !zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       /* When trying to create, create the VRF if it doesn't exist.
+        * Note: The VRF isn't active until we hear about it from the kernel.
+        */
+       if (!zvrf) {
+               vrf = vrf_get(VRF_UNKNOWN, vrf_name);
+               if (!vrf) {
+                       vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               zvrf = vrf->info;
+               if (!zvrf) {
+                       vty_out(vty, "%% Could not create vrf-info %s\n",
+                               vrf_name);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               /* Mark as having FRR configuration */
+               vrf_set_user_cfged(vrf);
+       }
        return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi,
                                       negate, dest_str, mask_str, src_str,
                                       gate_str, ifname, flag_str, tag_str,
@@ -2286,16 +2312,67 @@ DEFUN (show_vrf,
                else
                        vty_out(vty, "id %u table %u", zvrf_id(zvrf),
                                zvrf->table_id);
+               if (vrf_is_user_cfged(vrf))
+                       vty_out(vty, " (configured)");
                vty_out(vty, "\n");
        }
 
        return CMD_SUCCESS;
 }
 
+DEFUN (default_vrf_vni_mapping,
+       default_vrf_vni_mapping_cmd,
+       "vni " CMD_VNI_RANGE,
+       "VNI corresponding to the DEFAULT VRF\n"
+       "VNI-ID\n")
+{
+       int ret = 0;
+       char err[ERR_STR_SZ];
+       struct zebra_vrf *zvrf = NULL;
+       vni_t vni = strtoul(argv[1]->arg, NULL, 10);
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_default_vrf_vni_mapping,
+       no_default_vrf_vni_mapping_cmd,
+       "no vni " CMD_VNI_RANGE,
+       NO_STR
+       "VNI corresponding to DEFAULT VRF\n"
+       "VNI-ID")
+{
+       int ret = 0;
+       char err[ERR_STR_SZ];
+       vni_t vni = strtoul(argv[2]->arg, NULL, 10);
+       struct zebra_vrf *zvrf = NULL;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (vrf_vni_mapping,
        vrf_vni_mapping_cmd,
        "vni " CMD_VNI_RANGE,
-       "VNI\n"
+       "VNI corresponding to tenant VRF\n"
        "VNI-ID\n")
 {
        int ret = 0;
@@ -2307,6 +2384,8 @@ DEFUN (vrf_vni_mapping,
        assert(vrf);
        assert(zvrf);
 
+       /* Mark as having FRR configuration */
+       vrf_set_user_cfged(vrf);
        ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
        if (ret != 0) {
                vty_out(vty, "%s\n", err);
@@ -2320,7 +2399,7 @@ DEFUN (no_vrf_vni_mapping,
        no_vrf_vni_mapping_cmd,
        "no vni " CMD_VNI_RANGE,
        NO_STR
-       "VNI\n"
+       "VNI corresponding to tenant VRF\n"
        "VNI-ID")
 {
        int ret = 0;
@@ -2338,6 +2417,10 @@ DEFUN (no_vrf_vni_mapping,
                return CMD_WARNING;
        }
 
+       /* If no other FRR config for this VRF, mark accordingly. */
+       if (!zebra_vrf_has_config(zvrf))
+               vrf_reset_user_cfged(vrf);
+
        return CMD_SUCCESS;
 }
 
@@ -2361,29 +2444,16 @@ DEFUN (show_vrf_vni,
                json_vrfs = json_object_new_array();
        }
 
+       if (!uj)
+               vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n",
+                       "VRF", "VNI", "VxLAN IF", "L3-SVI", "State", "Rmac");
+
        RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
                zvrf = vrf->info;
                if (!zvrf)
                        continue;
 
-               if (!zvrf->l3vni)
-                       continue;
-
-               if (!uj) {
-                       vty_out(vty, "vrf: %s VNI: %u",
-                               zvrf_name(zvrf),
-                               zvrf->l3vni);
-                       vty_out(vty, "\n");
-               } else {
-                       json_object *json_vrf = NULL;
-
-                       json_vrf = json_object_new_object();
-                       json_object_string_add(json_vrf, "vrf",
-                                              zvrf_name(zvrf));
-                       json_object_int_add(json_vrf, "l3vni",
-                                           zvrf->l3vni);
-                       json_object_array_add(json_vrfs, json_vrf);
-               }
+               zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
        }
 
        if (uj) {
@@ -2396,6 +2466,19 @@ DEFUN (show_vrf_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (show_evpn_global,
+       show_evpn_global_cmd,
+       "show evpn [json]",
+       SHOW_STR
+       "EVPN\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+
+       zebra_vxlan_print_evpn(vty, uj);
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_evpn_vni,
        show_evpn_vni_cmd,
        "show evpn vni [json]",
@@ -2431,44 +2514,13 @@ DEFUN (show_evpn_vni_vni,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_l3vni,
-       show_evpn_l3vni_cmd,
-       "show evpn l3vni [json]",
-       SHOW_STR
-       "EVPN\n"
-       "L3 VNI\n"
-       JSON_STR)
-{
-       u_char uj = use_json(argc, argv);
-
-       zebra_vxlan_print_l3vnis(vty, uj);
-       return CMD_SUCCESS;
-}
-
-DEFUN (show_evpn_l3vni_vni,
-       show_evpn_l3vni_vni_cmd,
-       "show evpn l3vni " CMD_VNI_RANGE "[json]",
-       SHOW_STR
-       "EVPN\n"
-       "L3 VxLAN Network Identifier\n"
-       "VNI number\n"
-       JSON_STR)
-{
-       vni_t vni;
-       u_char uj = use_json(argc, argv);
-
-       vni = strtoul(argv[3]->arg, NULL, 10);
-       zebra_vxlan_print_l3vni(vty, vni, uj);
-       return CMD_SUCCESS;
-}
-
-DEFUN (show_evpn_rmac_l3vni_mac,
-       show_evpn_rmac_l3vni_mac_cmd,
-       "show evpn rmac l3vni " CMD_VNI_RANGE " mac WORD [json]",
+DEFUN (show_evpn_rmac_vni_mac,
+       show_evpn_rmac_vni_mac_cmd,
+       "show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]",
        SHOW_STR
        "EVPN\n"
        "RMAC\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "VNI number\n"
        "MAC\n"
        "mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n"
@@ -2487,13 +2539,13 @@ DEFUN (show_evpn_rmac_l3vni_mac,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_rmac_l3vni,
-       show_evpn_rmac_l3vni_cmd,
-       "show evpn rmac l3vni " CMD_VNI_RANGE "[json]",
+DEFUN (show_evpn_rmac_vni,
+       show_evpn_rmac_vni_cmd,
+       "show evpn rmac vni " CMD_VNI_RANGE "[json]",
        SHOW_STR
        "EVPN\n"
        "RMAC\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "VNI number\n"
        JSON_STR)
 {
@@ -2506,13 +2558,13 @@ DEFUN (show_evpn_rmac_l3vni,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_rmac_l3vni_all,
-       show_evpn_rmac_l3vni_all_cmd,
-       "show evpn rmac l3vni all [json]",
+DEFUN (show_evpn_rmac_vni_all,
+       show_evpn_rmac_vni_all_cmd,
+       "show evpn rmac vni all [json]",
        SHOW_STR
        "EVPN\n"
        "RMAC addresses\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "All VNIs\n"
        JSON_STR)
 {
@@ -2523,13 +2575,13 @@ DEFUN (show_evpn_rmac_l3vni_all,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_nh_l3vni_ip,
-       show_evpn_nh_l3vni_ip_cmd,
-       "show evpn next-hops l3vni " CMD_VNI_RANGE " ip WORD [json]",
+DEFUN (show_evpn_nh_vni_ip,
+       show_evpn_nh_vni_ip_cmd,
+       "show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]",
        SHOW_STR
        "EVPN\n"
        "Remote Vteps\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "VNI number\n"
        "Ip address\n"
        "Host address (ipv4 or ipv6)\n"
@@ -2550,13 +2602,13 @@ DEFUN (show_evpn_nh_l3vni_ip,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_nh_l3vni,
-       show_evpn_nh_l3vni_cmd,
-       "show evpn next-hops l3vni " CMD_VNI_RANGE "[json]",
+DEFUN (show_evpn_nh_vni,
+       show_evpn_nh_vni_cmd,
+       "show evpn next-hops vni " CMD_VNI_RANGE "[json]",
        SHOW_STR
        "EVPN\n"
        "Remote Vteps\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "VNI number\n"
        JSON_STR)
 {
@@ -2569,13 +2621,13 @@ DEFUN (show_evpn_nh_l3vni,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_evpn_nh_l3vni_all,
-       show_evpn_nh_l3vni_all_cmd,
-       "show evpn next-hops l3vni all [json]",
+DEFUN (show_evpn_nh_vni_all,
+       show_evpn_nh_vni_all_cmd,
+       "show evpn next-hops vni all [json]",
        SHOW_STR
        "EVPN\n"
        "Remote VTEPs\n"
-       "L3-VNI\n"
+       "L3 VNI\n"
        "All VNIs\n"
        JSON_STR)
 {
@@ -3283,16 +3335,15 @@ void zebra_vty_init(void)
        /* Commands for VRF */
        install_element(VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd);
 
+       install_element(VIEW_NODE, &show_evpn_global_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
-       install_element(VIEW_NODE, &show_evpn_l3vni_cmd);
-       install_element(VIEW_NODE, &show_evpn_l3vni_vni_cmd);
-       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_mac_cmd);
-       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_cmd);
-       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_all_cmd);
-       install_element(VIEW_NODE, &show_evpn_nh_l3vni_ip_cmd);
-       install_element(VIEW_NODE, &show_evpn_nh_l3vni_cmd);
-       install_element(VIEW_NODE, &show_evpn_nh_l3vni_all_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
@@ -3303,7 +3354,8 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
 
-       install_element(CONFIG_NODE, &no_vrf_vni_mapping_cmd);
+       install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
+       install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
        install_element(VRF_NODE, &vrf_vni_mapping_cmd);
        install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
 
index 1690079f68f76c7d0e7f67167f34976d58459d43..fb1aebecc3599596a7d200f2c013b88f220e0de2 100644 (file)
@@ -46,7 +46,6 @@
 #include "zebra/zebra_vxlan.h"
 #include "zebra/zebra_memory.h"
 #include "zebra/zebra_l2.h"
-#include "lib/json.h"
 
 DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
@@ -59,6 +58,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
 
 
 /* static function declarations */
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd);
 static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
 static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
 static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
@@ -286,6 +288,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
                                                         : "Inactive");
                }
        }
+       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
+               if (!json)
+                       vty_out(vty, " Default-gateway");
+               else
+                       json_object_boolean_true_add(json, "defaultGateway");
+       }
        if (json == NULL)
                vty_out(vty, "\n");
 }
@@ -442,7 +450,8 @@ static void zl3vni_print_nh(zebra_neigh_t *n,
                        ipaddr2str(&n->ip, buf2, sizeof(buf2)));
                vty_out(vty, "  RMAC: %s\n",
                       prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
-               vty_out(vty, "  Host-List:\n");
+               vty_out(vty, "  Refcount: %d\n", listcount(n->host_list));
+               vty_out(vty, "  Prefixes:\n");
                for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
                        vty_out(vty, "    %s\n",
                                prefix2str(p, buf2, sizeof(buf2)));
@@ -451,15 +460,16 @@ static void zl3vni_print_nh(zebra_neigh_t *n,
                json_object_string_add(json, "ip",
                                       ipaddr2str(&(n->ip), buf2,
                                                  sizeof(buf2)));
-               json_object_string_add(json, "rmac",
+               json_object_string_add(json, "routerMac",
                                       prefix_mac2str(&n->emac, buf2,
                                                      sizeof(buf2)));
+               json_object_int_add(json, "refCount", listcount(n->host_list));
                for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
                        json_object_array_add(json_hosts,
                                              json_object_new_string(
                                                        prefix2str(p, buf2,
                                                                sizeof(buf2))));
-               json_object_object_add(json, "hosts", json_hosts);
+               json_object_object_add(json, "prefixList", json_hosts);
        }
 }
 
@@ -479,24 +489,27 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac,
                        prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
                vty_out(vty, " Remote VTEP: %s\n",
                        inet_ntoa(zrmac->fwd_info.r_vtep_ip));
-               vty_out(vty, "  Host-List:\n");
+               vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list));
+               vty_out(vty, "  Prefixes:\n");
                for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
                        vty_out(vty, "    %s\n",
                                prefix2str(p, buf2, sizeof(buf2)));
        } else {
                json_hosts = json_object_new_array();
-               json_object_string_add(json, "Rmac",
+               json_object_string_add(json, "routerMac",
                                       prefix_mac2str(&zrmac->macaddr,
                                                      buf1,
                                                      sizeof(buf1)));
-               json_object_string_add(json, "vtep-ip",
+               json_object_string_add(json, "vtepIp",
                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               json_object_int_add(json, "refCount",
+                                   listcount(zrmac->host_list));
                for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
                        json_object_array_add(json_hosts,
                                              json_object_new_string(
                                                        prefix2str(p, buf2,
                                                                sizeof(buf2))));
-               json_object_object_add(json, "hosts", json_hosts);
+               json_object_object_add(json, "prefixList", json_hosts);
        }
 }
 
@@ -534,6 +547,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
                vty_out(vty, " Auto Mac ");
        }
 
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+               vty_out(vty, " Sticky Mac ");
+
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+               vty_out(vty, " Default-gateway Mac ");
+
        vty_out(vty, "\n");
        /* print all the associated neigh */
        vty_out(vty, " Neighbors:\n");
@@ -739,17 +758,15 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet,
                return;
 
        if (!json_vni) {
-               vty_out(vty, "%-15s %-17s %6d\n",
+               vty_out(vty, "%-15s %-17s\n",
                        ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
-                       prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
-                       listcount(n->host_list));
+                       prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
        } else {
-               json_object_string_add(json_nh, "nexthop-ip",
+               json_object_string_add(json_nh, "nexthopIp",
                                       ipaddr2str(&n->ip, buf2, sizeof(buf2)));
-               json_object_string_add(json_nh, "rmac",
+               json_object_string_add(json_nh, "routerMac",
                                       prefix_mac2str(&n->emac, buf1,
                                                      sizeof(buf1)));
-               json_object_int_add(json_nh, "refCnt", listcount(n->host_list));
                json_object_object_add(json_vni,
                                       ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
                                       json_nh);
@@ -789,10 +806,9 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet,
        if (json == NULL) {
                vty_out(vty, "\nVNI %u #Next-Hops %u\n\n",
                        zl3vni->vni, num_nh);
-               vty_out(vty, "%-15s %-17s %6s\n", "IP",
-                       "RMAC", "Refcnt");
+               vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
        } else
-               json_object_int_add(json_vni, "numNh", num_nh);
+               json_object_int_add(json_vni, "numNextHops", num_nh);
 
        memset(&wctx, 0, sizeof(struct nh_walk_ctx));
        wctx.vty = vty;
@@ -833,10 +849,9 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet,
        }
 
        if (json == NULL) {
-               vty_out(vty, "\nVNI %u #MACs %u\n\n",
+               vty_out(vty, "\nVNI %u #RMACs %u\n\n",
                        zl3vni->vni, num_rmacs);
-               vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
-                       "Remote VTEP", "Refcnt");
+               vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
        } else
                json_object_int_add(json_vni, "numRmacs", num_rmacs);
 
@@ -872,18 +887,15 @@ static void zl3vni_print_rmac_hash(struct hash_backet *backet,
                return;
 
        if (!json) {
-               vty_out(vty, "%-17s %-21s %-6d\n",
+               vty_out(vty, "%-17s %-21s\n",
                        prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
-                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip),
-                                       listcount(zrmac->host_list));
+                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
        } else {
-               json_object_string_add(json_rmac, "rmac",
+               json_object_string_add(json_rmac, "routerMac",
                                       prefix_mac2str(&zrmac->macaddr, buf,
                                                      sizeof(buf)));
-               json_object_string_add(json_rmac, "vtep-ip",
+               json_object_string_add(json_rmac, "vtepIp",
                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
-               json_object_int_add(json_rmac, "refcnt",
-                                   listcount(zrmac->host_list));
                json_object_object_add(json,
                                       prefix_mac2str(&zrmac->macaddr, buf,
                                                      sizeof(buf)),
@@ -906,7 +918,10 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
 
        if (!json) {
                vty_out(vty, "VNI: %u\n", zl3vni->vni);
-               vty_out(vty, "  Local Vtep Ip: %s",
+               vty_out(vty, "  Type: %s\n", "L3");
+               vty_out(vty, "  Tenant VRF: %s\n",
+                       zl3vni_vrf_name(zl3vni));
+               vty_out(vty, "  Local Vtep Ip: %s\n",
                        inet_ntoa(zl3vni->local_vtep_ip));
                vty_out(vty, "  Vxlan-Intf: %s\n",
                        zl3vni_vxlan_if_name(zl3vni));
@@ -914,35 +929,34 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
                        zl3vni_svi_if_name(zl3vni));
                vty_out(vty, "  State: %s\n",
                        zl3vni_state2str(zl3vni));
-               vty_out(vty, "  Vrf: %s\n",
-                       zl3vni_vrf_name(zl3vni));
-               vty_out(vty, "  Rmac: %s\n",
+               vty_out(vty, "  Router MAC: %s\n",
                        zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
-               vty_out(vty, "  L2-VNIs: ");
+               vty_out(vty, "  L2 VNIs: ");
                for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
                        vty_out(vty, "%u ", zvni->vni);
                vty_out(vty, "\n");
        } else {
                json_vni_list = json_object_new_array();
                json_object_int_add(json, "vni", zl3vni->vni);
-               json_object_string_add(json, "local-vtep-ip",
+               json_object_string_add(json, "type", "L3");
+               json_object_string_add(json, "localVtepIp",
                                       inet_ntoa(zl3vni->local_vtep_ip));
-               json_object_string_add(json, "vxlan-intf",
+               json_object_string_add(json, "vxlanIntf",
                                       zl3vni_vxlan_if_name(zl3vni));
-               json_object_string_add(json, "svi-if",
+               json_object_string_add(json, "sviIntf",
                                       zl3vni_svi_if_name(zl3vni));
                json_object_string_add(json, "state",
                                       zl3vni_state2str(zl3vni));
                json_object_string_add(json, "vrf",
                                       zl3vni_vrf_name(zl3vni));
-               json_object_string_add(json, "rmac",
+               json_object_string_add(json, "routerMac",
                                       zl3vni_rmac2str(zl3vni, buf,
                                                       sizeof(buf)));
                for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
                        json_object_array_add(json_vni_list,
                                              json_object_new_int(zvni->vni));
                }
-               json_object_object_add(json, "l2-vnis", json_vni_list);
+               json_object_object_add(json, "l2Vnis", json_vni_list);
        }
 }
 
@@ -964,9 +978,11 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
 
        if (json == NULL) {
                vty_out(vty, "VNI: %u\n", zvni->vni);
-               vty_out(vty, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
+               vty_out(vty, " Type: %s\n", "L2");
+               vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
        } else {
                json_object_int_add(json, "vni", zvni->vni);
+               json_object_string_add(json, "type", "L2");
                json_object_string_add(json, "vrf",
                                       vrf_id_to_name(zvni->vrf_id));
        }
@@ -978,11 +994,13 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
        }
        num_macs = num_valid_macs(zvni);
        num_neigh = hashcount(zvni->neigh_table);
-       if (json == NULL)
-               vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
-                       zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
+       if (json == NULL) {
+               vty_out(vty, " VxLAN interface: %s\n",
+                       zvni->vxlan_if->name);
+               vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
+               vty_out(vty," Local VTEP IP: %s\n",
                        inet_ntoa(zvni->local_vtep_ip));
-       else {
+       else {
                json_object_string_add(json, "vxlanInterface",
                                       zvni->vxlan_if->name);
                json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
@@ -1033,7 +1051,6 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
 static void zl3vni_print_hash(struct hash_backet *backet,
                              void *ctx[])
 {
-       char buf[ETHER_ADDR_STRLEN];
        struct vty *vty = NULL;
        json_object *json = NULL;
        json_object *json_vni = NULL;
@@ -1047,33 +1064,30 @@ static void zl3vni_print_hash(struct hash_backet *backet,
                return;
 
        if (!json) {
-               vty_out(vty, "%-10u %-15s %-20s %-20s %-5s %-37s %-18s\n",
-                       zl3vni->vni,
-                       inet_ntoa(zl3vni->local_vtep_ip),
+               vty_out(vty,
+                       "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n",
+                       zl3vni->vni, "L3",
                        zl3vni_vxlan_if_name(zl3vni),
-                       zl3vni_svi_if_name(zl3vni),
-                       zl3vni_state2str(zl3vni),
-                       zl3vni_vrf_name(zl3vni),
-                       zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+                       hashcount(zl3vni->rmac_table),
+                       hashcount(zl3vni->nh_table),
+                       "n/a",
+                       zl3vni_vrf_name(zl3vni));
        } else {
                char vni_str[VNI_STR_LEN];
 
                snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
                json_vni = json_object_new_object();
                json_object_int_add(json_vni, "vni", zl3vni->vni);
-               json_object_string_add(json_vni, "local-ip",
-                                      inet_ntoa(zl3vni->local_vtep_ip));
-               json_object_string_add(json_vni, "vxlan-if",
+               json_object_string_add(json_vni, "vxlanIf",
                                       zl3vni_vxlan_if_name(zl3vni));
-               json_object_string_add(json_vni, "svi-if",
-                                      zl3vni_svi_if_name(zl3vni));
-               json_object_string_add(json_vni, "state",
-                                      zl3vni_state2str(zl3vni));
-               json_object_string_add(json_vni, "vrf",
+               json_object_int_add(json_vni, "numMacs",
+                                   hashcount(zl3vni->rmac_table));
+               json_object_int_add(json_vni, "numArpNd",
+                                   hashcount(zl3vni->nh_table));
+               json_object_string_add(json_vni, "numRemoteVteps", "n/a");
+               json_object_string_add(json_vni, "type", "L3");
+               json_object_string_add(json_vni, "tenantVrf",
                                       zl3vni_vrf_name(zl3vni));
-               json_object_string_add(json_vni, "rmac",
-                                      zl3vni_rmac2str(zl3vni, buf,
-                                                      sizeof(buf)));
                json_object_object_add(json, vni_str, json_vni);
        }
 
@@ -1111,24 +1125,26 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[])
        num_macs = num_valid_macs(zvni);
        num_neigh = hashcount(zvni->neigh_table);
        if (json == NULL)
-               vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u %-37s\n",
-                       zvni->vni,
+               vty_out(vty,
+                       "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
+                       zvni->vni, "L2",
                        zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
-                       inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
-                       num_vteps,
+                       num_macs, num_neigh, num_vteps,
                        vrf_id_to_name(zvni->vrf_id));
        else {
                char vni_str[VNI_STR_LEN];
                snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
                json_vni = json_object_new_object();
+               json_object_int_add(json_vni, "vni", zvni->vni);
+               json_object_string_add(json_vni, "type", "L2");
                json_object_string_add(json_vni, "vxlanIf",
                                       zvni->vxlan_if ? zvni->vxlan_if->name
                                                      : "unknown");
-               json_object_string_add(json_vni, "vtepIp",
-                                      inet_ntoa(zvni->local_vtep_ip));
                json_object_int_add(json_vni, "numMacs", num_macs);
                json_object_int_add(json_vni, "numArpNd", num_neigh);
                json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
+               json_object_string_add(json_vni, "tenantVrf",
+                                      vrf_id_to_name(zvni->vrf_id));
                if (num_vteps) {
                        json_vtep_list = json_object_new_array();
                        for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
@@ -1409,7 +1425,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
 
                                ZEBRA_NEIGH_SET_ACTIVE(n);
                                zvni_neigh_send_add_to_client(
-                                       zvni->vni, &n->ip, &n->emac, 0);
+                                       zvni->vni, &n->ip, &n->emac, n->flags);
                        } else {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
@@ -1519,8 +1535,14 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
  */
 static int zvni_neigh_send_add_to_client(vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr, u_char flags)
+                                        struct ethaddr *macaddr,
+                                        u_char neigh_flags)
 {
+       u_char                  flags = 0;
+
+       if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
                                             ZEBRA_MACIP_ADD);
 }
@@ -1692,7 +1714,37 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
 
                zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
        }
+       return 0;
+}
+
+
+static int zvni_advertise_subnet(zebra_vni_t *zvni,
+                                struct interface *ifp,
+                                int advertise)
+{
+       struct listnode *cnode = NULL, *cnnode = NULL;
+       struct connected *c = NULL;
+       struct ethaddr macaddr;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+               struct prefix p;
 
+               memcpy(&p, c->address, sizeof(struct prefix));
+
+               /* skip link local address */
+               if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
+                       continue;
+
+               apply_mask(&p);
+               if (advertise)
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                    ZEBRA_IP_PREFIX_ROUTE_ADD);
+               else
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                ZEBRA_IP_PREFIX_ROUTE_DEL);
+       }
        return 0;
 }
 
@@ -1729,6 +1781,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
        /* Set "local" forwarding info. */
        SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
        SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
        memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
        mac->fwd_info.local.ifindex = ifp->ifindex;
        mac->fwd_info.local.vid = vxl->access_vlan;
@@ -1748,9 +1801,14 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
 
        /* Set "local" forwarding info. */
        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+       SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
        memcpy(&n->emac, macaddr, ETH_ALEN);
        n->ifindex = ifp->ifindex;
 
+       /* Only advertise in BGP if the knob is enabled */
+       if (!advertise_gw_macip_enabled(zvni))
+               return 0;
+
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
                        "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP",
@@ -1759,7 +1817,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
                        ipaddr2str(ip, buf2, sizeof(buf2)));
 
        zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
-                                     ZEBRA_MAC_TYPE_GW);
+                                     n->flags);
 
        return 0;
 }
@@ -1793,16 +1851,21 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
        if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
                return -1;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug(
-                       "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP",
-                       ifp->name, ifp->ifindex, zvni->vni,
-                       prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
-                       ipaddr2str(ip, buf2, sizeof(buf2)));
-
-       /* Remove neighbor from BGP. */
-       zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
-                                     ZEBRA_MAC_TYPE_GW);
+       /* 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_MACIP_TYPE_GW);
+       }
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
@@ -1869,9 +1932,6 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
        if (!zvni)
                return;
 
-       if (!advertise_gw_macip_enabled(zvni))
-               return;
-
        ifp = zvni->vxlan_if;
        if (!ifp)
                return;
@@ -1985,7 +2045,6 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
 {
        struct mac_walk_ctx *wctx = arg;
        zebra_mac_t *mac = backet->data;
-       u_char sticky = 0;
 
        if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
            || ((wctx->flags & DEL_REMOTE_MAC)
@@ -1995,11 +2054,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
                && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
                                  &wctx->r_vtep_ip))) {
                if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
-                       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1
-                                                                         : 0;
                        zvni_mac_send_del_to_client(
                                wctx->zvni->vni, &mac->macaddr,
-                               (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+                               mac->flags);
                }
 
                if (wctx->uninstall)
@@ -2074,8 +2131,16 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
  * Inform BGP about local MAC addition.
  */
 static int zvni_mac_send_add_to_client(vni_t vni,
-                                      struct ethaddr *macaddr, u_char flags)
+                                      struct ethaddr *macaddr,
+                                      u_char mac_flags)
 {
+       u_char  flags = 0;
+
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_ADD);
 }
@@ -2084,8 +2149,16 @@ static int zvni_mac_send_add_to_client(vni_t vni,
  * Inform BGP about local MAC deletion.
  */
 static int zvni_mac_send_del_to_client(vni_t vni,
-                                      struct ethaddr *macaddr, u_char flags)
+                                      struct ethaddr *macaddr,
+                                      u_char mac_flags)
 {
+       u_char  flags = 0;
+
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_DEL);
 }
@@ -2393,15 +2466,13 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni,
        vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
        if (vlan_if) {
 
-               if (advertise_gw_macip_enabled(zvni)) {
-                       /* Add SVI MAC-IP */
-                       zvni_add_macip_for_intf(vlan_if, zvni);
+               /* Add SVI MAC-IP */
+               zvni_add_macip_for_intf(vlan_if, zvni);
 
-                       /* Add VRR MAC-IP - if any*/
-                       vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
-                       if (vrr_if)
-                               zvni_add_macip_for_intf(vrr_if, zvni);
-               }
+               /* Add VRR MAC-IP - if any*/
+               vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+               if (vrr_if)
+                       zvni_add_macip_for_intf(vrr_if, zvni);
 
                neigh_read_for_vlan(zns, vlan_if);
        }
@@ -2795,17 +2866,19 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
 /*
  * Cleanup VNI/VTEP and update kernel
  */
-static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
+static void zvni_cleanup_all(struct hash_backet *backet, void *arg)
 {
        zebra_vni_t *zvni = NULL;
        zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
 
        zvni = (zebra_vni_t *)backet->data;
        if (!zvni)
                return;
 
        /* remove from l3-vni list */
-       zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
        if (zl3vni)
                listnode_delete(zl3vni->l2vnis, zvni);
 
@@ -3158,13 +3231,13 @@ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni,
 static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni,
                               zebra_neigh_t *n)
 {
-       if (!is_l3vni_oper_up(zl3vni))
-               return -1;
-
        if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
            !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
                return 0;
 
+       if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
+               return 0;
+
        return kernel_del_neigh(zl3vni->svi_if, &n->ip);
 }
 
@@ -3712,6 +3785,63 @@ static void zl3vni_del_nh_hash_entry(struct hash_backet *backet,
        zl3vni_nh_del(zl3vni, n);
 }
 
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd)
+{
+       struct zserv *client = NULL;
+       struct stream *s = NULL;
+       char buf[PREFIX_STRLEN];
+
+       client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
+       /* BGP may not be running. */
+       if (!client)
+               return 0;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, vrf_id);
+       stream_put(s, p, sizeof(struct prefix));
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                          "Send ip prefix %s %s on vrf %s",
+                          prefix2str(p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
+               client->prefixadd_cnt++;
+       else
+               client->prefixdel_cnt++;
+
+       return zebra_server_send_message(client);
+}
+
+/* re-add remote rmac if needed */
+static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
+                                 struct ethaddr *rmac)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       zebra_mac_t *zrmac = NULL;
+
+       zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+       if (!zrmac)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("Del remote RMAC %s L3VNI %u - readd",
+                          prefix_mac2str(rmac, buf, sizeof(buf)),
+                          zl3vni->vni);
+
+       zl3vni_rmac_install(zl3vni, zrmac);
+       return 0;
+}
+
 /* Public functions */
 
 /* handle evpn route in vrf table */
@@ -3834,8 +3964,7 @@ void zebra_vxlan_print_rmacs_l3vni(struct vty *vty,
                vty_out(vty,
                        "Number of Remote RMACs known for this VNI: %u\n",
                        num_rmacs);
-               vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
-                       "Remote VTEP", "Refcnt");
+               vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP");
        } else
                json_object_int_add(json, "numRmacs", num_rmacs);
 
@@ -3966,10 +4095,9 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty,
                vty_out(vty,
                        "Number of NH Neighbors known for this VNI: %u\n",
                        num_nh);
-               vty_out(vty, "%-15s %-17s %6s\n", "IP",
-                       "RMAC", "Refcnt");
+               vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
        } else
-               json_object_int_add(json, "numNh", num_nh);
+               json_object_int_add(json, "numNextHops", num_nh);
 
        hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
 
@@ -4053,52 +4181,40 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json)
        }
 }
 
-/*
- * Display L3 VNI hash table (VTY command handler).
- */
-void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json)
+void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                              json_object *json_vrfs)
 {
-       u_int32_t num_vnis;
-       void *args[2];
-       json_object *json = NULL;
-       struct zebra_ns *zns = NULL;
-
-       if (!is_evpn_enabled()) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
-               return;
-       }
-
-       zns = zebra_ns_lookup(NS_DEFAULT);
-       assert(zns);
+       char buf[ETHER_ADDR_STRLEN];
+       zebra_l3vni_t *zl3vni = NULL;
 
-       num_vnis = hashcount(zns->l3vni_table);
-       if (!num_vnis) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
+       zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
                return;
-       }
 
-       if (use_json) {
-               json = json_object_new_object();
-               json_object_int_add(json, "numVnis", num_vnis);
+       if (!json_vrfs) {
+               vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n",
+                       zvrf_name(zvrf),
+                       zl3vni->vni,
+                       zl3vni_vxlan_if_name(zl3vni),
+                       zl3vni_svi_if_name(zl3vni),
+                       zl3vni_state2str(zl3vni),
+                       zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
        } else {
-               vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis);
-               vty_out(vty, "%-10s %-15s %-20s %-20s %-5s %-37s %-18s\n",
-                       "VNI", "Local-ip", "Vx-intf", "L3-SVI", "State",
-                       "VRF", "Rmac");
-       }
-
-       args[0] = vty;
-       args[1] = json;
-       hash_iterate(zns->l3vni_table,
-                    (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
-                    args);
-
-       if (use_json) {
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
-               json_object_free(json);
+               json_object *json_vrf = NULL;
+               json_vrf = json_object_new_object();
+               json_object_string_add(json_vrf, "vrf",
+                                      zvrf_name(zvrf));
+               json_object_int_add(json_vrf, "vni", zl3vni->vni);
+               json_object_string_add(json_vrf, "vxlanIntf",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_string_add(json_vrf, "sviIntf",
+                                      zl3vni_svi_if_name(zl3vni));
+               json_object_string_add(json_vrf, "state",
+                                      zl3vni_state2str(zl3vni));
+               json_object_string_add(json_vrf, "routerMac",
+                                      zl3vni_rmac2str(zl3vni, buf,
+                                                      sizeof(buf)));
+               json_object_array_add(json_vrfs, json_vrf);
        }
 }
 
@@ -4467,25 +4583,45 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
 void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
                           u_char use_json)
 {
-       zebra_vni_t *zvni;
        json_object *json = NULL;
        void *args[2];
 
        if (!is_evpn_enabled())
                return;
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
-               else
-                       vty_out(vty, "%% VNI %u does not exist\n", vni);
-               return;
-       }
+
        if (use_json)
                json = json_object_new_object();
        args[0] = vty;
        args[1] = json;
-       zvni_print(zvni, (void *)args);
+
+       if (is_vni_l3(vni)) {
+               zebra_l3vni_t *zl3vni = NULL;
+
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       if (use_json)
+                               vty_out(vty, "{}\n");
+                       else
+                               vty_out(vty, "%% VNI %u does not exist\n", vni);
+                       return;
+               }
+
+               zl3vni_print(zl3vni, (void *)args);
+       } else {
+               zebra_vni_t *zvni;
+
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       if (use_json)
+                               vty_out(vty, "{}\n");
+                       else
+                               vty_out(vty, "%% VNI %u does not exist\n", vni);
+                       return;
+               }
+
+               zvni_print(zvni, (void *)args);
+       }
+
        if (use_json) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -4493,44 +4629,91 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
        }
 }
 
-/*
- * Display VNI hash table (VTY command handler).
- */
-void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
-                           u_char use_json)
+/* Display all global details for EVPN */
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
 {
-       u_int32_t num_vnis;
+       int num_l2vnis = 0;
+       int num_l3vnis = 0;
+       int num_vnis = 0;
        json_object *json = NULL;
-       void *args[2];
+       struct zebra_ns *zns = NULL;
+       struct zebra_vrf *zvrf = NULL;
 
        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) {
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       num_l3vnis = hashcount(zns->l3vni_table);
+       num_l2vnis = hashcount(zvrf->vni_table);
+       num_vnis = num_l2vnis + num_l3vnis;
+
+       if (uj) {
                json = json_object_new_object();
                json_object_string_add(json, "advertiseGatewayMacip",
                                       zvrf->advertise_gw_macip ? "Yes" : "No");
                json_object_int_add(json, "numVnis", num_vnis);
+               json_object_int_add(json, "numL2Vnis", num_l2vnis);
+               json_object_int_add(json, "numL3Vnis", num_l3vnis);
        } else {
+               vty_out(vty, "L2 VNIs: %u\n", num_l2vnis);
+               vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
                vty_out(vty, "Advertise gateway mac-ip: %s\n",
                        zvrf->advertise_gw_macip ? "Yes" : "No");
-               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");
        }
+
+       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)
+{
+       json_object *json = NULL;
+       struct zebra_ns *zns = NULL;
+       void *args[2];
+
+       if (!is_evpn_enabled())
+               return;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       if (!zns)
+               return;
+
+
+       if (use_json)
+               json = json_object_new_object();
+       else
+               vty_out(vty,
+                       "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n",
+                       "VNI", "Type", "VxLAN IF", "# MACs",
+                       "# ARPs", "# Remote VTEPs", "Tenant VRF");
+
        args[0] = vty;
        args[1] = json;
 
+       /* Display all L2-VNIs */
        hash_iterate(zvrf->vni_table,
                     (void (*)(struct hash_backet *, void *))zvni_print_hash,
                     args);
 
+       /* Display all L3-VNIs */
+       hash_iterate(zns->l3vni_table,
+                    (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
+                    args);
+
        if (use_json) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -4768,7 +4951,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
                           zvni->vni);
        ZEBRA_NEIGH_SET_ACTIVE(n);
 
-       return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
+       return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
 }
 
 
@@ -4879,6 +5062,17 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length,
                if (!mac && !n)
                        continue;
 
+               /* Ignore the delete if this mac is a gateway mac-ip */
+               if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
+                   CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
+                       zlog_err("%u: Ignore Del for  MAC %s neigh %s on VNI %u as it is configured as a default gateway",
+                                zvrf_id(zvrf),
+                                prefix_mac2str(&macaddr, buf, sizeof(buf)),
+                                ipaddr2str(&ip, buf1, sizeof(buf1)),
+                                vni);
+                       continue;
+               }
+
                /* Uninstall remote neighbor or MAC. */
                if (n) {
                        /* When the MAC changes for an IP, it is possible the
@@ -4936,7 +5130,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
        int update_mac = 0, update_neigh = 0;
        char buf[ETHER_ADDR_STRLEN];
        char buf1[INET6_ADDRSTRLEN];
-       u_char sticky;
+       u_char sticky = 0;
+       u_char flags = 0;
        struct interface *ifp = NULL;
        struct zebra_if *zif = NULL;
 
@@ -4973,17 +5168,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
                STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
                l += IPV4_MAX_BYTELEN;
 
-               /* Get 'sticky' flag. */
-               STREAM_GETC(s, sticky);
+               /* Get flags - sticky mac and/or gateway mac */
+               flags = stream_getc(s);
+               sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
                l++;
 
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
-                               "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
-                               sticky ? "sticky " : "",
+                               "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
                                prefix_mac2str(&macaddr, buf, sizeof(buf)),
                                ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
-                               inet_ntoa(vtep_ip),
+                               inet_ntoa(vtep_ip), flags,
                                zebra_route_string(client->proto));
 
                /* Locate VNI hash entry - expected to exist. */
@@ -5025,13 +5220,26 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
                        zvni_vtep_install(zvni, &vtep_ip);
                }
 
-               /* First, check if the remote MAC is unknown or has a change. If
-                * so,
-                * that needs to be updated first. Note that client could
-                * install
-                * MAC and MACIP separately or just install the latter.
-                */
                mac = zvni_mac_lookup(zvni, &macaddr);
+
+               /* Ignore the update if the mac is already present
+                  as a gateway mac */
+               if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
+                   CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac", 
+                                          zvrf_id(zvrf),
+                                          prefix_mac2str(&macaddr,
+                                                         buf, sizeof(buf)),
+                                          ipaddr2str(&ip, buf1,
+                                                     sizeof(buf1)), vni);
+                       continue;
+               }
+
+               /* check if the remote MAC is unknown or has a change.
+                * If so, that needs to be updated first. Note that client could
+                * install MAC and MACIP separately or just install the latter.
+                */
                if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
                    || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
                               != sticky
@@ -5146,7 +5354,6 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
        zebra_vni_t *zvni;
        zebra_mac_t *mac;
        char buf[ETHER_ADDR_STRLEN];
-       u_char sticky;
 
        zif = ifp->info;
        assert(zif);
@@ -5178,9 +5385,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
                        ifp->name, ifp->ifindex, vni);
 
        /* Remove MAC from BGP. */
-       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvni->vni, macaddr,
-                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+       zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
 
        /*
         * If there are no neigh associated with the mac delete the mac
@@ -5205,11 +5410,12 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
                                       struct interface *br_if,
                                       struct ethaddr *macaddr, vlanid_t vid)
 {
-       struct zebra_if *zif;
-       struct zebra_l2info_vxlan *vxl;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
        vni_t vni;
-       zebra_vni_t *zvni;
-       zebra_mac_t *mac;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+       zebra_mac_t *mac = NULL;
        char buf[ETHER_ADDR_STRLEN];
 
        zif = ifp->info;
@@ -5221,6 +5427,11 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
        if (!is_evpn_enabled())
                return 0;
 
+       /* check if this is a remote RMAC and readd simillar to remote macs */
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni)
+               return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
+
        /* Locate hash entry; it is expected to exist. */
        zvni = zvni_lookup(vni);
        if (!zvni)
@@ -5253,7 +5464,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
        zebra_vni_t *zvni;
        zebra_mac_t *mac;
        char buf[ETHER_ADDR_STRLEN];
-       u_char sticky;
 
        /* We are interested in MACs only on ports or (port, VLAN) that
         * map to a VNI.
@@ -5282,9 +5492,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
                return 0;
 
        /* Remove MAC from BGP. */
-       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvni->vni, macaddr,
-                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+       zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
 
        /* Update all the neigh entries associated with this mac */
        zvni_process_neigh_on_local_mac_del(zvni, mac);
@@ -5423,7 +5631,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
        if (add) {
                zvni_process_neigh_on_local_mac_add(zvni, mac);
                return zvni_mac_send_add_to_client(zvni->vni, macaddr,
-                                                  sticky);
+                                                  mac->flags);
        }
 
        return 0;
@@ -5687,10 +5895,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
        }
 
 
-       /* check if we are advertising gw macip routes */
-       if (!advertise_gw_macip_enabled(zvni))
-               return 0;
-
        memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
 
        if (p->family == AF_INET) {
@@ -6394,17 +6598,115 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
        return 0;
 }
 
-int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf)
 {
        zebra_l3vni_t *zl3vni = NULL;
 
-       zl3vni = zl3vni_from_vrf(zvrf_id(zvrf));
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
        if (!zl3vni)
                return 0;
 
+       zl3vni->vrf_id = zvrf_id(zvrf);
+       if (is_l3vni_oper_up(zl3vni))
+               zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       return 0;
+}
+
+int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
+               return 0;
+
+       zl3vni->vrf_id = VRF_UNKNOWN;
        zebra_vxlan_process_l3vni_oper_down(zl3vni);
+       return 0;
+}
+
+int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       vni_t vni;
+
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
+               return 0;
+
+       vni = zl3vni->vni;
        zl3vni_del(zl3vni);
-       zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0);
+       zebra_vxlan_handle_vni_transition(zvrf, vni, 0);
+
+       return 0;
+}
+
+/*
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
+ */
+int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                struct zebra_vrf *zvrf)
+{
+       struct stream *s;
+       int advertise;
+       vni_t vni = 0;
+       zebra_vni_t *zvni = NULL;
+       struct interface *ifp = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan zl2_info;
+       struct interface *vlan_if = NULL;
+
+       if (zvrf_id(zvrf) != VRF_DEFAULT) {
+               zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
+                        zvrf_id(zvrf));
+               return -1;
+       }
+
+       s = client->ibuf;
+       advertise = stream_getc(s);
+       vni = stream_get3(s);
+
+       zvni = zvni_lookup(vni);
+       if (!zvni)
+               return 0;
+
+       if (zvni->advertise_subnet == advertise)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "EVPN subnet Adv %s on VNI %d , currently %s",
+                       advertise ? "enabled" : "disabled", vni,
+                       zvni->advertise_subnet ? "enabled" : "disabled");
+
+
+       zvni->advertise_subnet = advertise;
+
+       ifp = zvni->vxlan_if;
+       if (!ifp)
+               return 0;
+
+       zif = ifp->info;
+
+       /* If down or not mapped to a bridge, we're done. */
+       if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+               return 0;
+
+       zl2_info = zif->l2info.vxl;
+
+       vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+                                 zif->brslave_info.br_if);
+       if (!vlan_if)
+               return 0;
+
+       if (zvni->advertise_subnet)
+               zvni_advertise_subnet(zvni, vlan_if, 1);
+       else
+               zvni_advertise_subnet(zvni, vlan_if, 0);
 
        return 0;
 }
@@ -6590,6 +6892,14 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
                                      "Zebra VRF VNI Table");
 }
 
+/* Cleanup VNI info, but don't free the table. */
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+       if (!zvrf)
+               return;
+       hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+}
+
 /* Close all VNI handling */
 void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
 {
index b7def6acf8cbd12106a925240390dff51ec8ee55..d9801a8b6059d4bcbeec9f569aa249a8781653e2 100644 (file)
@@ -31,6 +31,7 @@
 #include "vlan.h"
 #include "vxlan.h"
 
+#include "lib/json.h"
 #include "zebra/zebra_vrf.h"
 
 /* Is EVPN enabled? */
@@ -53,8 +54,12 @@ is_evpn_enabled()
 
 extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
 extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
 extern void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
                                                struct ipaddr *ip, u_char uj);
+extern void zebra_vxlan_print_evpn(struct vty *vty, u_char uj);
 extern void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
                                                  struct ethaddr *rmac,
                                                  u_char use_json);
@@ -99,9 +104,8 @@ extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni, u_char
 extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, u_char use_json);
 extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni,
                                    u_char use_json);
-extern void zebra_vxlan_print_l3vnis(struct vty *vty,
-                                    u_char use_json);
-
+extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                                     json_object *json_vrfs);
 extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
                                        int add);
 extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
@@ -140,6 +144,8 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
 extern int zebra_vxlan_remote_vtep_del(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                       struct zebra_vrf *zvrf);
 extern int zebra_vxlan_advertise_gw_macip(struct zserv *client,
                                          u_short length,
                                          struct zebra_vrf *zvrf);
@@ -151,6 +157,7 @@ extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
                                           int err_str_sz, int add);
 extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf);
 extern void zebra_vxlan_close_tables(struct zebra_vrf *);
+extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
 extern void zebra_vxlan_ns_init(struct zebra_ns *zns);
 extern void zebra_vxlan_ns_disable(struct zebra_ns *zns);
 extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
index db828c337e239eb54d31f195970fb096a34aa82a..0eb880e848abd8539efff69079237fd18e79a2ff 100644 (file)
@@ -83,6 +83,10 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf)
 {
 }
 
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
+{
+}
+
 void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char)
 {
 }
@@ -103,10 +107,6 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni)
 {
 }
 
-void zebra_vxlan_print_l3vnis(struct vty *vty)
-{
-}
-
 int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
 {
        return 0;
@@ -207,3 +207,7 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
 void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
 {
 }
+
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+}
index ef6f9b99cb765c7e1ef6b33158609e4af38a6a67..8d34b3e2f12bbc613b51ec50231fc1b8f4322af8 100644 (file)
@@ -70,6 +70,9 @@ struct zebra_vni_t_ {
        /* Flag for advertising gw macip */
        u_int8_t advertise_gw_macip;
 
+       /* Flag for advertising gw macip */
+       u_int8_t advertise_subnet;
+
        /* Corresponding VxLAN interface. */
        struct interface *vxlan_if;
 
@@ -233,6 +236,7 @@ struct zebra_mac_t_ {
 #define ZEBRA_MAC_AUTO    0x04  /* Auto created for neighbor. */
 #define ZEBRA_MAC_STICKY  0x08  /* Static MAC */
 #define ZEBRA_MAC_REMOTE_RMAC  0x10  /* remote router mac */
+#define ZEBRA_MAC_DEF_GW  0x20
 
        /* Local or remote info. */
        union {
@@ -314,6 +318,7 @@ struct zebra_neigh_t_ {
 #define ZEBRA_NEIGH_LOCAL     0x01
 #define ZEBRA_NEIGH_REMOTE    0x02
 #define ZEBRA_NEIGH_REMOTE_NH    0x04 /* neigh entry for remote vtep */
+#define ZEBRA_NEIGH_DEF_GW    0x08
 
        enum zebra_neigh_state state;
 
index 3ee2bb59ecef2a5d637f6190f84cf81388572c36..71437bab1544eda7b5039d9070bf069cb7a7b1a5 100644 (file)
@@ -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;
index 4b3b0041b845faa8fd7d227c8b15705fac96ecf3..7d5f6b45437f203c23c6b3f7d1e8e1e27239cb11 100644 (file)
@@ -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;