]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: advertise VNI subnet
authorMitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>
Mon, 20 Nov 2017 05:47:04 +0000 (21:47 -0800)
committermitesh <mitesh@cumulusnetworks.com>
Tue, 23 Jan 2018 23:58:53 +0000 (15:58 -0800)
In EVPN symmetric routing, not all subnets are presents everywhere.
We have multiple scenarios where a host might not get learned locally.
1. GARP miss
2. SVI down/up
3. Silent host

We need a mechanism to resolve such hosts. In order to achieve this,
we will be advertising a subnet route from a box and that box will help
in resolving the ARP to such hosts.

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
15 files changed:
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_route.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
lib/log.c
lib/zclient.c
lib/zclient.h
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index b20076d471950765eb24d1a66dee42aa84d4f802..1a9b26764c3e147f8219933b826a8c39a6de7bbe 100644 (file)
@@ -3188,20 +3188,20 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
  */
 
 /* withdraw type-5 route corresponding to ip prefix */
-void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
                                   afi_t afi, safi_t safi)
 {
        int ret = 0;
        struct prefix_evpn evp;
        char buf[PREFIX_STRLEN];
 
-       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       build_type5_prefix_from_ip_prefix(&evp, p);
        ret = delete_evpn_type5_route(bgp_vrf, &evp);
        if (ret) {
                zlog_err(
                         "%u failed to delete type-5 route for prefix %s in vrf %s",
                         bgp_vrf->vrf_id,
-                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        prefix2str(p, buf, sizeof(buf)),
                         vrf_id_to_name(bgp_vrf->vrf_id));
        }
 }
@@ -3218,12 +3218,12 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
 
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi);
+               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
 
 }
 
 /* advertise ip prefix as type-5 route*/
-void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
                                    afi_t afi, safi_t safi)
 {
        int ret = 0;
@@ -3233,20 +3233,17 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
        if (!advertise_type5_routes(bgp_vrf, afi))
                return;
 
-       if (!rn->info)
-               return;
-
        /* only advertise subnet routes as type-5 */
-       if (is_host_route(&rn->p))
+       if (is_host_route(p))
                return;
 
-       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       build_type5_prefix_from_ip_prefix(&evp, p);
        ret = update_evpn_type5_route(bgp_vrf, &evp);
        if (ret) {
                zlog_err(
                         "%u failed to create type-5 route for prefix %s in vrf %s",
                         bgp_vrf->vrf_id,
-                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        prefix2str(p, buf, sizeof(buf)),
                         vrf_id_to_name(bgp_vrf->vrf_id));
        }
 }
@@ -3259,8 +3256,12 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
        struct bgp_node *rn = NULL;
 
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+
+               if (!rn->info)
+                       continue;
+               bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, afi, safi);
+       }
 }
 
 void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
index b3b61db141d4204d13e8e4cd40b2b738f47cd2d8..cff9d65468f2a7ce22d58e3aeefff02d7c042c63 100644 (file)
@@ -56,10 +56,10 @@ static inline vni_t label2vni(mpls_label_t *label)
 }
 
 extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
-                                          struct bgp_node *rn,
+                                          struct prefix *p,
                                           afi_t afi, safi_t safi);
 extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
-                                         struct bgp_node *rn,
+                                         struct prefix *p,
                                          afi_t afi, safi_t safi);
 extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
                                           safi_t safi);
index 6003e03f356955f91181c4988906991094825f63..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;
 
index b463896c493345f2825bd40a734bc50bb8e18a14..932046f7e076739803ac6d4a4a1fdb9ada384a6c 100644 (file)
@@ -2271,6 +2271,32 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
        return;
 }
 
+/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_set_advertise_subnet(struct bgp *bgp,
+                                     struct bgpevpn *vpn)
+{
+       if (vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 1;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
+/*
+ * evpn - disable advertisement of default g/w
+ */
+static void evpn_unset_advertise_subnet(struct bgp *bgp,
+                                       struct bgpevpn *vpn)
+{
+       if (!vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 0;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
 /*
  * EVPN (VNI advertisement) enabled. Register with zebra.
  */
@@ -2330,6 +2356,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
                if (vpn->advertise_gw_macip)
                        vty_out(vty, "   advertise-default-gw\n");
 
+               if (vpn->advertise_subnet)
+                       vty_out(vty, "   advertise-subnet\n");
+
                vty_out(vty, "  exit-vni\n");
        }
 }
@@ -2440,6 +2469,56 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_advertise_vni_subnet,
+       bgp_evpn_advertise_vni_subnet_cmd,
+       "advertise-subnet",
+       "Advertise the subnet corresponding to VNI\n")
+{
+       struct bgp *bgp_vrf = NULL;
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       if (!(advertise_type5_routes(bgp_vrf, AFI_IP) ||
+             advertise_type5_routes(bgp_vrf, AFI_IP6))) {
+               vty_out(vty,
+                       "%%Please enable ip prefix advertisement under l2vpn evpn in %s",
+                       vrf_id_to_name(bgp_vrf->vrf_id));
+               return CMD_WARNING;
+       }
+
+       evpn_set_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_vni_subnet,
+       no_bgp_evpn_advertise_vni_subnet_cmd,
+       "no advertise-subnet",
+       NO_STR
+       "Advertise All local VNIs\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       evpn_unset_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
 DEFUN (bgp_evpn_advertise_type5,
        bgp_evpn_advertise_type5_cmd,
        "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
@@ -4118,5 +4197,8 @@ void bgp_ethernetvpn_init(void)
                        &bgp_evpn_advertise_default_gw_vni_cmd);
        install_element(BGP_EVPN_VNI_NODE,
                        &no_bgp_evpn_advertise_default_gw_vni_cmd);
+       install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
+       install_element(BGP_EVPN_VNI_NODE,
+                       &no_bgp_evpn_advertise_vni_subnet_cmd);
 #endif
 }
index 234bde418b735c1f69621d18dde3c1a7c01dde2e..7ee84c3531876a39f3fea10ae637c39fe2f20c09 100644 (file)
@@ -2226,9 +2226,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
        /* advertise/withdraw type-5 routes */
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
                if (new_select)
-                       bgp_evpn_advertise_type5_route(bgp, rn, afi, safi);
+                       bgp_evpn_advertise_type5_route(bgp, &rn->p, afi, safi);
                else if (old_select)
-                       bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi);
+                       bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
        }
 
        /* Clear any route change flags. */
index 2a35645ee83b32eb590cd086a33e6aeaa123f740..970b3eefbfe5cb8f624b3e980ebfcb603e327c40 100644 (file)
@@ -1635,6 +1635,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
        zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
 }
 
+int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni)
+{
+       struct stream *s = NULL;
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return 0;
+
+       /* Don't try to register if Zebra doesn't know of this instance. */
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+               return 0;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_ADVERTISE_SUBNET, bgp->vrf_id);
+       stream_putc(s, advertise);
+       stream_put3(s, vni);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
 {
        struct stream *s = NULL;
@@ -1821,6 +1844,53 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
 }
 
+static void bgp_zebra_process_local_ip_prefix(int cmd,
+                                             struct zclient *zclient,
+                                             zebra_size_t length,
+                                             vrf_id_t vrf_id)
+{
+       struct stream *s = NULL;
+       struct bgp *bgp_vrf = NULL;
+       struct prefix p;
+       char buf[PREFIX_STRLEN];
+
+       memset(&p, 0, sizeof(struct prefix));
+       s = zclient->ibuf;
+       stream_get(&p, s, sizeof(struct prefix));
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp_vrf)
+               return;
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("Recv prefix %s %s on vrf %s",
+                          prefix2str(&p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) {
+
+               if (p.family == AF_INET)
+                       return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
+                                                             AFI_IP,
+                                                             SAFI_UNICAST);
+               else
+                       return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
+                                                             AFI_IP6,
+                                                             SAFI_UNICAST);
+
+       } else {
+               if (p.family == AF_INET)
+                       return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
+                                                            AFI_IP,
+                                                            SAFI_UNICAST);
+               else
+                       return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
+                                                            AFI_IP6,
+                                                            SAFI_UNICAST);
+       }
+}
+
 extern struct zebra_privs_t bgpd_privs;
 
 void bgp_zebra_init(struct thread_master *master)
@@ -1853,6 +1923,8 @@ void bgp_zebra_init(struct thread_master *master)
        zclient->local_macip_del = bgp_zebra_process_local_macip;
        zclient->local_l3vni_add = bgp_zebra_process_local_l3vni;
        zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
+       zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
+       zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
 }
 
 void bgp_zebra_destroy(void)
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 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 a4bd2bda32b1cb2a606d0744ca4d3e27367d47fc..a4fa0966a7c9a8c9d2dbdbb2427d40dae0b0ce08 100644 (file)
@@ -2234,6 +2234,16 @@ static int zclient_read(struct thread *thread)
                        (*zclient->local_macip_del)(command, zclient, length,
                                                    vrf_id);
                break;
+       case ZEBRA_IP_PREFIX_ROUTE_ADD:
+               if (zclient->local_ip_prefix_add)
+                       (*zclient->local_ip_prefix_add)(command, zclient,
+                                                       length, vrf_id);
+               break;
+       case ZEBRA_IP_PREFIX_ROUTE_DEL:
+               if (zclient->local_ip_prefix_del)
+                       (*zclient->local_ip_prefix_del)(command, zclient,
+                                                       length, vrf_id);
+               break;
        case ZEBRA_PW_STATUS_UPDATE:
                if (zclient->pw_status_update)
                        (*zclient->pw_status_update)(command, zclient, length,
index 892e0ea99417da343a4b237fa964aeb1f251726a..8554f3e39dc528c051cab571d503fe3899e25b11 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);
index 1d70e970ec8b507c297de159e2e303653b69a094..6b92d80953ddf81493ea835939720bef9f12e80d 100644 (file)
@@ -59,6 +59,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
 
 
 /* static function declarations */
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd);
 static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
 static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
 static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
@@ -1710,7 +1713,37 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
 
                zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
        }
+       return 0;
+}
+
+
+static int zvni_advertise_subnet(zebra_vni_t *zvni,
+                                struct interface *ifp,
+                                int advertise)
+{
+       struct listnode *cnode = NULL, *cnnode = NULL;
+       struct connected *c = NULL;
+       struct ethaddr macaddr;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+               struct prefix p;
 
+               memcpy(&p, c->address, sizeof(struct prefix));
+
+               /* skip link local address */
+               if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
+                       continue;
+
+               apply_mask(&p);
+               if (advertise)
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                    ZEBRA_IP_PREFIX_ROUTE_ADD);
+               else
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                ZEBRA_IP_PREFIX_ROUTE_DEL);
+       }
        return 0;
 }
 
@@ -3749,6 +3782,43 @@ static void zl3vni_del_nh_hash_entry(struct hash_backet *backet,
        zl3vni_nh_del(zl3vni, n);
 }
 
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd)
+{
+       struct zserv *client = NULL;
+       struct stream *s = NULL;
+       char buf[PREFIX_STRLEN];
+
+       client = zebra_find_client(ZEBRA_ROUTE_BGP);
+       /* BGP may not be running. */
+       if (!client)
+               return 0;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zserv_create_header(s, cmd, vrf_id);
+       stream_put(s, p, sizeof(struct prefix));
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                          "Send ip prefix %s %s on vrf %s",
+                          prefix2str(p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
+               client->prefixadd_cnt++;
+       else
+               client->prefixdel_cnt++;
+
+       return zebra_server_send_message(client);
+}
+
 /* Public functions */
 
 /* handle evpn route in vrf table */
@@ -6461,6 +6531,73 @@ int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
        return 0;
 }
 
+/*
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
+ */
+int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                struct zebra_vrf *zvrf)
+{
+       struct stream *s;
+       int advertise;
+       vni_t vni = 0;
+       zebra_vni_t *zvni = NULL;
+       struct interface *ifp = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan zl2_info;
+       struct interface *vlan_if = NULL;
+
+       if (zvrf_id(zvrf) != VRF_DEFAULT) {
+               zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
+                        zvrf_id(zvrf));
+               return -1;
+       }
+
+       s = client->ibuf;
+       advertise = stream_getc(s);
+       vni = stream_get3(s);
+
+       zvni = zvni_lookup(vni);
+       if (!zvni)
+               return 0;
+
+       if (zvni->advertise_subnet == advertise)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "EVPN subnet Adv %s on VNI %d , currently %s",
+                       advertise ? "enabled" : "disabled", vni,
+                       zvni->advertise_subnet ? "enabled" : "disabled");
+
+
+       zvni->advertise_subnet = advertise;
+
+       ifp = zvni->vxlan_if;
+       if (!ifp)
+               return 0;
+
+       zif = ifp->info;
+
+       /* If down or not mapped to a bridge, we're done. */
+       if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+               return 0;
+
+       zl2_info = zif->l2info.vxl;
+
+       vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+                                 zif->brslave_info.br_if);
+       if (!vlan_if)
+               return 0;
+
+       if (zvni->advertise_subnet)
+               zvni_advertise_subnet(zvni, vlan_if, 1);
+       else
+               zvni_advertise_subnet(zvni, vlan_if, 0);
+
+       return 0;
+}
+
 /*
  * Handle message from client to enable/disable advertisement of g/w macip
  * routes
index b7def6acf8cbd12106a925240390dff51ec8ee55..4e1eedd0dceff3bfa2b33cb6931ba971c78449de 100644 (file)
@@ -140,6 +140,8 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
 extern int zebra_vxlan_remote_vtep_del(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                       struct zebra_vrf *zvrf);
 extern int zebra_vxlan_advertise_gw_macip(struct zserv *client,
                                          u_short length,
                                          struct zebra_vrf *zvrf);
index ecbdbfd83541d18f5c7c1b63b0db5219e763548b..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;
 
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;