]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd/zebra/lib: EVPN support for asymmetric VxLan routing
authorMitesh Kanjariya <mitesh@marvel-07.cumulusnetworks.com>
Wed, 28 Jun 2017 08:51:10 +0000 (01:51 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 8 Aug 2017 14:28:46 +0000 (10:28 -0400)
1. Advertise gateway mac-ip in EVPN
2. Advertise VRR mac-ip in EVPN
3. Ignore gateway mac-ip advertisements in case of distributed gateway
4. Config knob to enable/disable gateway mac-ip advertisements

Ticket: CM-16456, CM-16543, CM-16555, CM-16778
Review: CCR-6283
Unit-test: Manual

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

index 7a5e370bcf9655a50c2ecabb3934fd61bbc862c8..ab3307a6a76b3aa8e4a1d3cc98ec80ec624ef4d2 100644 (file)
@@ -704,7 +704,7 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn)
 static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                                   afi_t afi, safi_t safi, struct bgp_node *rn,
                                   struct attr *attr, int add, int vni_table,
-                                  struct bgp_info **ri)
+                                  struct bgp_info **ri, u_char flags)
 {
        struct bgp_info *tmp_ri;
        struct bgp_info *local_ri, *remote_ri;
@@ -751,8 +751,11 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                 * remote, we have to initiate appropriate MAC mobility steps.
                 * This
                 * is applicable when updating the VNI routing table.
+                * We need to skip mobility steps for g/w macs (local mac on g/w
+                * SVI) advertised in EVPN.
+                * This will ensure that local routes are preferred for g/w macs
                 */
-               if (remote_ri) {
+               if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
                        u_int32_t cur_seqnum;
 
                        /* Add MM extended community to route. */
@@ -811,7 +814,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
  * and schedule for processing.
  */
 static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
-                            struct prefix_evpn *p, u_char sticky)
+                            struct prefix_evpn *p, u_char flags)
 {
        struct bgp_node *rn;
        struct attr attr;
@@ -828,7 +831,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        attr.nexthop = vpn->originator_ip;
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
-       attr.sticky = sticky;
+       attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
 
        /* Set up RT and ENCAP extended community. */
        build_evpn_route_extcomm(vpn, &attr);
@@ -839,7 +842,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
 
        /* Create or update route entry. */
        route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
-                                              1, 1, &ri);
+                                              1, 1, &ri, flags);
        assert(ri);
        attr_new = ri->attr;
 
@@ -860,7 +863,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
                rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
                                      (struct prefix *)p, &vpn->prd);
                update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0,
-                                       &global_ri);
+                                       &global_ri, flags);
 
                /* Schedule for processing and unlock node. */
                bgp_process(bgp, rn, afi, safi);
@@ -998,10 +1001,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
 
                if (evpn_route_is_sticky(bgp, rn))
                        update_evpn_route_entry(bgp, vpn, afi, safi, rn,
-                                               &attr_sticky, 0, 1, &ri);
+                                               &attr_sticky, 0, 1, &ri, 0);
                else
                        update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
-                                               0, 1, &ri);
+                                               0, 1, &ri, 0);
 
                /* If a local route exists for this prefix, we need to update
                 * the global routing table too.
@@ -1022,7 +1025,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
                                         (struct prefix *)evp, &vpn->prd);
                assert(rd_rn);
                update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0,
-                                       0, &global_ri);
+                                       0, &global_ri, 0);
 
                /* Schedule for processing and unlock node. */
                bgp_process(bgp, rd_rn, afi, safi);
@@ -1631,8 +1634,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
 
        global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
                                     (struct prefix *)&p, &vpn->prd);
-       update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0,
-                               &ri);
+       update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, &ri,
+                               0);
 
        /* Schedule for processing and unlock node. */
        bgp_process(bgp, global_rn, afi, safi);
@@ -1665,7 +1668,7 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
                                             (struct prefix *)evp, &vpn->prd);
                assert(global_rn);
                update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1,
-                                       0, &global_ri);
+                                       0, &global_ri, 0);
 
                /* Schedule for processing and unlock node. */
                bgp_process(bgp, global_rn, afi, safi);
@@ -2586,7 +2589,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
  * Handle add of a local MACIP.
  */
 int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
-                            struct ipaddr *ip, u_char sticky)
+                            struct ipaddr *ip, u_char flags)
 {
        struct bgpevpn *vpn;
        struct prefix_evpn p;
@@ -2606,13 +2609,17 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
 
        /* Create EVPN type-2 route and schedule for processing. */
        build_evpn_type2_prefix(&p, mac, ip);
-       if (update_evpn_route(bgp, vpn, &p, sticky)) {
+       if (update_evpn_route(bgp, vpn, &p, flags)) {
                char buf[ETHER_ADDR_STRLEN];
                char buf2[INET6_ADDRSTRLEN];
 
                zlog_err(
-                       "%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s",
-                       bgp->vrf_id, vpn->vni, sticky ? "sticky" : "",
+                       "%u:Failed to create Type-2 route, VNI %u %s %s MAC %s IP %s",
+                       bgp->vrf_id, vpn->vni,
+                       CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky "
+                                                                : "",
+                       CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "gateway "
+                                                                : "",
                        prefix_mac2str(mac, buf, sizeof(buf)),
                        ipaddr2str(ip, buf2, sizeof(buf2)));
                return -1;
index f4c7e68a5d76a17052b2ec39a0986a1a564d6988..e9b7857212cd79db3979b0fe612a7bc4dc0c4752 100644 (file)
@@ -42,7 +42,7 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
                                    struct ethaddr *mac, struct ipaddr *ip);
 extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
                                    struct ethaddr *mac, struct ipaddr *ip,
-                                   u_char sticky);
+                                   u_char flags);
 extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
 extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                                  struct in_addr originator_ip);
index 095dfa1b15049ab646f44c66d65dc753d70e27ef..e6f6301405b1de827fd34f90962f2e1eb393c5f3 100644 (file)
@@ -58,6 +58,9 @@ struct bgpevpn {
 #define VNI_FLAG_IMPRT_CFGD        0x8  /* Import RT is user configured */
 #define VNI_FLAG_EXPRT_CFGD        0x10 /* Export RT is user configured */
 
+       /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
+       u_int8_t advertise_gw_macip;
+
        /* Id for deriving the RD automatically for this VNI */
        u_int16_t rd_id;
 
index c3eb32b91dd0e85d624aa578e7b44c696aaf54fd..b5c17cf9aa3e06ab1b0f7aaa5d98f12ade4bb262 100644 (file)
@@ -1641,6 +1641,51 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp)
                     vty);
 }
 
+/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
+{
+       if (!vpn) {
+               if (bgp->advertise_gw_macip)
+                       return;
+
+               bgp->advertise_gw_macip = 1;
+               bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
+       } else {
+               if (vpn->advertise_gw_macip)
+                       return;
+
+               vpn->advertise_gw_macip = 1;
+               bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
+                                            vpn->vni);
+       }
+       return;
+}
+
+/*
+ * evpn - disable advertisement of default g/w
+ */
+static void evpn_unset_advertise_default_gw(struct bgp *bgp,
+                                           struct bgpevpn *vpn)
+{
+       if (!vpn) {
+               if (!bgp->advertise_gw_macip)
+                       return;
+
+               bgp->advertise_gw_macip = 0;
+               bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
+       } else {
+               if (!vpn->advertise_gw_macip)
+                       return;
+
+               vpn->advertise_gw_macip = 0;
+               bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
+                                            vpn->vni);
+       }
+       return;
+}
+
 /*
  * EVPN (VNI advertisement) enabled. Register with zebra.
  */
@@ -1694,12 +1739,15 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write)
                                               ecom)) {
                                ecom_str = ecommunity_ecom2str(
                                        ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
-                               vty_out(vty, "   route-target export %s\n",
+                               vty_out(vty, "  route-target export %s\n",
                                        ecom_str);
                                XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
                        }
                }
 
+               if (vpn->advertise_gw_macip)
+                       vty_out(vty, "   advertise-default-gw\n");
+
                vty_out(vty, "  exit-vni\n");
        }
 }
@@ -1712,6 +1760,77 @@ static void write_vni_config_for_entry(struct hash_backet *backet,
 }
 
 #if defined(HAVE_CUMULUS)
+DEFUN (bgp_evpn_advertise_default_gw_vni,
+       bgp_evpn_advertise_default_gw_vni_cmd,
+       "advertise-default-gw",
+       "Advertise defualt g/w mac-ip routes in EVPN for a VNI\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_set_advertise_default_gw(bgp, vpn);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_default_vni_gw,
+       no_bgp_evpn_advertise_default_gw_vni_cmd,
+       "no advertise-default-gw",
+       NO_STR
+       "Withdraw default g/w mac-ip routes from EVPN for a VNI\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_default_gw(bgp, vpn);
+
+       return CMD_SUCCESS;
+}
+
+
+DEFUN (bgp_evpn_advertise_default_gw,
+       bgp_evpn_advertise_default_gw_cmd,
+       "advertise-default-gw",
+       "Advertise All defualt g/w mac-ip routes in EVPN\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       evpn_set_advertise_default_gw(bgp, NULL);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_default_gw,
+       no_bgp_evpn_advertise_default_gw_cmd,
+       "no advertise-default-gw",
+       NO_STR
+       "Withdraw All default g/w mac-ip routes from EVPN\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       evpn_unset_advertise_default_gw(bgp, NULL);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (bgp_evpn_advertise_all_vni,
        bgp_evpn_advertise_all_vni_cmd,
        "advertise-all-vni",
@@ -1764,6 +1883,9 @@ DEFUN (show_bgp_l2vpn_evpn_vni,
                return CMD_WARNING;
 
        if (argc == ((idx + 1) + 1)) {
+               vty_out(vty, "Advertise gateway macip flag: %s\n",
+                       bgp->advertise_gw_macip ? "Enabled" : "Disabled");
+
                /* Display all VNIs */
                vty_out(vty, "Advertise All VNI flag: %s\n",
                        bgp->advertise_all_vni ? "Enabled" : "Disabled");
@@ -2544,6 +2666,11 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
                bgp_config_write_family_header(vty, afi, safi, write);
                vty_out(vty, "  advertise-all-vni\n");
        }
+
+       if (bgp->advertise_gw_macip) {
+               bgp_config_write_family_header(vty, afi, safi, write);
+               vty_out(vty, "  advertise-default-gw\n");
+       }
 }
 
 void bgp_ethernetvpn_init(void)
@@ -2569,6 +2696,8 @@ void bgp_ethernetvpn_init(void)
 #if defined(HAVE_CUMULUS)
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
+       install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
 
        /* "show bgp l2vpn evpn" commands. */
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
@@ -2592,5 +2721,9 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
        install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
        install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
+       install_element(BGP_EVPN_VNI_NODE,
+                       &bgp_evpn_advertise_default_gw_vni_cmd);
+       install_element(BGP_EVPN_VNI_NODE,
+                       &no_bgp_evpn_advertise_default_gw_vni_cmd);
 #endif
 }
index 5071be909e61c775da096b6e5028e0b77e67e04e..2fc75ea5a23c4f9075ba541fbac71a7be4ea7a40 100644 (file)
@@ -2034,6 +2034,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_gw_macip(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_DEFAULT_GW, 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_all_vni(struct bgp *bgp, int advertise)
 {
        struct stream *s;
@@ -2120,7 +2143,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
        int ipa_len;
        char buf[ETHER_ADDR_STRLEN];
        char buf1[INET6_ADDRSTRLEN];
-       u_char sticky;
+       u_char flags;
 
        memset(&ip, 0, sizeof(ip));
        s = zclient->ibuf;
@@ -2140,21 +2163,20 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                        (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6;
                stream_get(&ip.ip.addr, s, ipa_len);
        }
-       sticky = stream_getc(s);
+       flags = stream_getc(s);
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
        if (!bgp)
                return 0;
 
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("%u:Recv MACIP %s %sMAC %s IP %s VNI %u", vrf_id,
-                          (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
-                          sticky ? "sticky " : "",
-                          prefix_mac2str(&mac, buf, sizeof(buf)),
+               zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u",
+                          vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+                          flags, prefix_mac2str(&mac, buf, sizeof(buf)),
                           ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
 
        if (command == ZEBRA_MACIP_ADD)
-               return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, sticky);
+               return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags);
        else
                return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
 }
index 8e55eb6d8df532b6cf36e1216b46b5461615ac2a..11405d1c1b47569f6e024a3e4978669b50cbce10 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _QUAGGA_BGP_ZEBRA_H
 #define _QUAGGA_BGP_ZEBRA_H
 
+#include "vxlan.h"
+
 extern void bgp_zebra_init(struct thread_master *master);
 extern void bgp_zebra_destroy(void);
 extern int bgp_if_update_all(void);
@@ -57,6 +59,7 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t,
 extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t,
                                                 vrf_id_t);
 
+extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
 extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
 
 extern int bgp_zebra_num_connects(void);
index 7992075af178c794b456f3ba2f5a3b68b5e40abe..bfdddc69b1e93bb901bbcbfa48cc4a65c943aa93 100644 (file)
@@ -380,6 +380,9 @@ struct bgp {
        /* EVI hash table */
        struct hash *vnihash;
 
+       /* EVPN enable - advertise gateway macip routes */
+       int advertise_gw_macip;
+
        /* EVPN enable - advertise local VNIs and their MACs etc. */
        int advertise_all_vni;
 
index 5adb06d28cc7717f23ec65cb2f9f1e0e90d64035..522aa9e7ac7598874a2060f3ed840107f043d0a1 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -908,6 +908,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
        DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
        DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
+       DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
        DESC_ENTRY(ZEBRA_VNI_ADD),
        DESC_ENTRY(ZEBRA_VNI_DEL),
        DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD),
index 435d26e2f9c28523c3142c2c81fe2fd5a1db7be9..67da45e13f0dec09750b7926c4a2f02db59de30c 100644 (file)
@@ -97,6 +97,7 @@ typedef enum {
        ZEBRA_FEC_REGISTER,
        ZEBRA_FEC_UNREGISTER,
        ZEBRA_FEC_UPDATE,
+       ZEBRA_ADVERTISE_DEFAULT_GW,
        ZEBRA_ADVERTISE_ALL_VNI,
        ZEBRA_VNI_ADD,
        ZEBRA_VNI_DEL,
@@ -266,6 +267,10 @@ struct zapi_ipv4 {
        vrf_id_t vrf_id;
 };
 
+/* Zebra MAC types */
+#define ZEBRA_MAC_TYPE_STICKY                0x01 /* Sticky MAC*/
+#define ZEBRA_MAC_TYPE_GW                    0x02 /* gateway (SVI) mac*/
+
 /* Prototypes of zebra client service functions. */
 extern struct zclient *zclient_new(struct thread_master *);
 extern void zclient_init(struct zclient *, int, u_short);
index a46657dd2ebfa4f7d97e042a6f6cdd3df6e52ae8..8064071c3794a9b7ba1b2d791feb6d6a65470b6c 100644 (file)
@@ -251,6 +251,8 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
                *zif_type = ZEBRA_IF_VLAN;
        else if (strcmp(kind, "vxlan") == 0)
                *zif_type = ZEBRA_IF_VXLAN;
+       else if (strcmp(kind, "macvlan") == 0)
+               *zif_type = ZEBRA_IF_MACVLAN;
 }
 
 // Temporary Assignments to compile on older platforms.
index ea722646968734db70acbdab0004b84c3781c0ed..970c3c52927b78fe5d67883cb245ba679628273c 100644 (file)
@@ -186,11 +186,12 @@ struct rtadvconf {
 
 /* Zebra interface type - ones of interest. */
 typedef enum {
-       ZEBRA_IF_VXLAN,  /* VxLAN interface */
-       ZEBRA_IF_VRF,    /* VRF device */
-       ZEBRA_IF_BRIDGE, /* bridge device */
-       ZEBRA_IF_VLAN,   /* VLAN sub-interface */
-       ZEBRA_IF_OTHER,  /* Anything else */
+       ZEBRA_IF_VXLAN,   /* VxLAN interface */
+       ZEBRA_IF_VRF,     /* VRF device */
+       ZEBRA_IF_BRIDGE,  /* bridge device */
+       ZEBRA_IF_VLAN,    /* VLAN sub-interface */
+       ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
+       ZEBRA_IF_OTHER,   /* Anything else */
 } zebra_iftype_t;
 
 /* Zebra "slave" interface type */
@@ -295,6 +296,9 @@ static inline void zebra_if_set_ziftype(struct interface *ifp,
 #define IS_ZEBRA_IF_VXLAN(ifp)                                                 \
        (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN)
 
+#define IS_ZEBRA_IF_MACVLAN(ifp)                                               \
+       (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_MACVLAN)
+
 #define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)                                          \
        (((struct zebra_if *)(ifp->info))->zif_slave_type                      \
         == ZEBRA_IF_SLAVE_BRIDGE)
index c3bbf40b3f0da91433a38e05cff5446dcb609a8c..92da5fe0ce6b58773ff30df3ed5153804fe27321 100644 (file)
@@ -41,6 +41,7 @@
 #include "zebra/debug.h"
 #include "zebra/router-id.h"
 #include "zebra/zebra_memory.h"
+#include "zebra/zebra_vxlan.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -402,6 +403,8 @@ void zebra_interface_address_add_update(struct interface *ifp,
                zlog_warn(
                        "WARNING: advertising address to clients that is not yet usable.");
 
+       zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1);
+
        router_id_add_address(ifc);
 
        for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
@@ -428,6 +431,8 @@ void zebra_interface_address_delete_update(struct interface *ifp,
                           prefix2str(p, buf, sizeof(buf)), ifc->ifp->name);
        }
 
+       zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0);
+
        router_id_del_address(ifc);
 
        for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
index eb0687bf8a6c2812ec8cf43a35aba9e0dd0bce3b..720268d3608ee2eb2577548e5057495df73c61d8 100644 (file)
@@ -102,6 +102,11 @@ struct zebra_vrf {
         */
        int advertise_all_vni;
 
+       /*
+        * Whether we are advertising g/w macip in EVPN or not.
+        */
+       int advertise_gw_macip;
+
        /* Route Installs */
        uint64_t installs;
        uint64_t removals;
index 523225bf365cfcc5c654e8862280836d1ceeb2e7..ee9a88c66c3ad1dde5d53b443b2f902e902d4c74 100644 (file)
@@ -68,7 +68,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt);
 
 static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ethaddr *macaddr,
-                                        struct ipaddr *ip, u_char sticky,
+                                        struct ipaddr *ip, u_char flags,
                                         u_int16_t cmd);
 static unsigned int neigh_hash_keymake(void *p);
 static int neigh_cmp(const void *p1, const void *p2);
@@ -83,10 +83,10 @@ static void zvni_neigh_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
 static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
 static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr);
+                                        struct ethaddr *macaddr, u_char flags);
 static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr);
+                                        struct ethaddr *macaddr, u_char flags);
 static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
 static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
 static zebra_vni_t *zvni_map_svi(struct interface *ifp,
@@ -106,9 +106,9 @@ static void zvni_mac_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
                             int uninstall, int upd_client, u_int32_t flags);
 static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
 static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
-                                      struct ethaddr *macaddr, u_char sticky);
+                                      struct ethaddr *macaddr, u_char flags);
 static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
-                                      struct ethaddr *macaddr, u_char sticky);
+                                      struct ethaddr *macaddr, u_char flags);
 static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
                                  struct interface *br_if, vlanid_t vid);
 static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac);
@@ -131,10 +131,31 @@ static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
 static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall);
 static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip);
 static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
-
+static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
+static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
+static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
+                            struct ethaddr *macaddr, struct ipaddr *ip);
+static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
+                            struct ipaddr *ip);
+struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
+static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf,
+                                     zebra_vni_t *zvni);
+static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
+                             int uninstall);
 
 /* Private functions */
 
+static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, zebra_vni_t *zvni)
+{
+       if (zvrf && zvrf->advertise_gw_macip)
+               return 1;
+
+       if (zvni && zvni->advertise_gw_macip)
+               return 1;
+
+       return 0;
+}
+
 /*
  * Helper function to determine maximum width of neighbor IP address for
  * display - just because we're dealing with IPv6 addresses that can
@@ -450,7 +471,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt)
  */
 static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ethaddr *macaddr,
-                                        struct ipaddr *ip, u_char sticky,
+                                        struct ipaddr *ip, u_char flags,
                                         u_int16_t cmd)
 {
        struct zserv *client;
@@ -483,19 +504,18 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
        } else
                stream_putl(s, 0); /* Just MAC. */
 
-       stream_putc(s, sticky); /* Sticky MAC? */
+       stream_putc(s, flags); /* sticky mac/gateway mac */
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("%u:Send MACIP %s %sMAC %s IP %s VNI %u to %s",
-                          zvrf_id(zvrf),
-                          (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
-                          sticky ? "sticky " : "",
-                          prefix_mac2str(macaddr, buf, sizeof(buf)),
-                          ipaddr2str(ip, buf2, sizeof(buf2)), vni,
-                          zebra_route_string(client->proto));
+               zlog_debug(
+                       "%u:Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s",
+                       zvrf_id(zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+                       flags, prefix_mac2str(macaddr, buf, sizeof(buf)),
+                       ipaddr2str(ip, buf2, sizeof(buf2)), vni,
+                       zebra_route_string(client->proto));
 
        if (cmd == ZEBRA_MACIP_ADD)
                client->macipadd_cnt++;
@@ -597,8 +617,9 @@ static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg)
                && (n->flags & ZEBRA_NEIGH_REMOTE)
                && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
                if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
-                       zvni_neigh_send_del_to_client(
-                               wctx->zvrf, wctx->zvni->vni, &n->ip, &n->emac);
+                       zvni_neigh_send_del_to_client(wctx->zvrf,
+                                                     wctx->zvni->vni, &n->ip,
+                                                     &n->emac, 0);
 
                if (wctx->uninstall)
                        zvni_neigh_uninstall(wctx->zvni, n);
@@ -676,9 +697,9 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
  */
 static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr)
+                                        struct ethaddr *macaddr, u_char flags)
 {
-       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0,
+       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags,
                                             ZEBRA_MACIP_ADD);
 }
 
@@ -687,9 +708,9 @@ static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
  */
 static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr)
+                                        struct ethaddr *macaddr, u_char flags)
 {
-       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0,
+       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags,
                                             ZEBRA_MACIP_DEL);
 }
 
@@ -770,6 +791,309 @@ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt)
                zvni_neigh_install(wctx->zvni, n);
 }
 
+/* Get the VRR interface for SVI if any */
+struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp)
+{
+       struct zebra_vrf *zvrf = NULL;
+       struct interface *tmp_if = NULL;
+       struct zebra_if *zif = NULL;
+       struct listnode *node;
+
+       zvrf = vrf_info_lookup(ifp->vrf_id);
+       assert(zvrf);
+
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) {
+               zif = tmp_if->info;
+               if (!zif)
+                       continue;
+
+               if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
+                       continue;
+
+               if (zif->link == ifp)
+                       return tmp_if;
+       }
+
+       return NULL;
+}
+
+static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
+{
+       struct zebra_vrf *zvrf = NULL;
+       struct listnode *cnode = NULL, *cnnode = NULL;
+       struct connected *c = NULL;
+       struct ethaddr macaddr;
+
+       zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+               struct ipaddr ip;
+
+               memset(&ip, 0, sizeof(struct ipaddr));
+               if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+                       continue;
+
+               if (c->address->family == AF_INET) {
+                       ip.ipa_type = IPADDR_V4;
+                       memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+                              sizeof(struct in_addr));
+               } else if (c->address->family == AF_INET6) {
+                       ip.ipa_type = IPADDR_V6;
+                       memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+                              sizeof(struct in6_addr));
+               } else {
+                       continue;
+               }
+
+               zvni_gw_macip_del(ifp, zvni, &ip);
+       }
+
+       return 0;
+}
+
+static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
+{
+       struct zebra_vrf *zvrf = NULL;
+       struct listnode *cnode = NULL, *cnnode = NULL;
+       struct connected *c = NULL;
+       struct ethaddr macaddr;
+
+       zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+               struct ipaddr ip;
+
+               memset(&ip, 0, sizeof(struct ipaddr));
+               if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+                       continue;
+
+               if (c->address->family == AF_INET) {
+                       ip.ipa_type = IPADDR_V4;
+                       memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+                              sizeof(struct in_addr));
+               } else if (c->address->family == AF_INET6) {
+                       ip.ipa_type = IPADDR_V6;
+                       memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+                              sizeof(struct in6_addr));
+               } else {
+                       continue;
+               }
+
+               zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
+       }
+
+       return 0;
+}
+
+/*
+ * zvni_gw_macip_add_to_client
+ */
+static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
+                            struct ethaddr *macaddr, struct ipaddr *ip)
+{
+       struct zebra_vrf *zvrf = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_neigh_t *n = NULL;
+       zebra_mac_t *mac = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       zif = zvni->vxlan_if->info;
+       if (!zif)
+               return -1;
+
+       vxl = &zif->l2info.vxl;
+
+       mac = zvni_mac_lookup(zvni, macaddr);
+       if (!mac) {
+               mac = zvni_mac_add(zvni, macaddr);
+               if (!mac) {
+                       zlog_err("%u:Failed to add MAC %s intf %s(%u) VID %u",
+                                ifp->vrf_id,
+                                prefix_mac2str(macaddr, buf, sizeof(buf)),
+                                ifp->name, ifp->ifindex, vxl->access_vlan);
+                       return -1;
+               }
+       }
+
+       /* Set "local" forwarding info. */
+       SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+       SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+       mac->fwd_info.local.ifindex = ifp->ifindex;
+       mac->fwd_info.local.vid = vxl->access_vlan;
+
+       n = zvni_neigh_lookup(zvni, ip);
+       if (!n) {
+               n = zvni_neigh_add(zvni, ip);
+               if (!n) {
+                       zlog_err(
+                               "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+                               ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)),
+                               prefix_mac2str(macaddr, NULL,
+                                              ETHER_ADDR_STRLEN),
+                               ifp->name, ifp->ifindex, zvni->vni);
+                       return -1;
+               }
+       }
+
+       /* Set "local" forwarding info. */
+       SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+       memcpy(&n->emac, macaddr, ETH_ALEN);
+       n->ifindex = ifp->ifindex;
+
+       /* We have a neigh associated to mac increment the refcnt*/
+       mac->neigh_refcnt++;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                       "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP",
+                       ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
+                       prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN),
+                       ipaddr2str(ip, buf2, sizeof(buf2)));
+
+       zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr,
+                                     ZEBRA_MAC_TYPE_GW);
+
+       return 0;
+}
+
+/*
+ * zvni_gw_macip_del_from_client
+ */
+static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
+                            struct ipaddr *ip)
+{
+       struct zebra_vrf *zvrf = NULL;
+       zebra_neigh_t *n = NULL;
+       zebra_mac_t *mac = NULL;
+       char buf2[INET6_ADDRSTRLEN];
+
+       zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       /* If the neigh entry is not present nothing to do*/
+       n = zvni_neigh_lookup(zvni, ip);
+       if (!n)
+               return 0;
+
+       /* mac entry should be present */
+       mac = zvni_mac_lookup(zvni, &n->emac);
+       if (!mac)
+               zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u",
+                        ifp->vrf_id,
+                        prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN),
+                        ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+
+       /* If the entry is not local nothing to do*/
+       if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+               return -1;
+
+       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(zvrf, zvni->vni, &n->ip, &n->emac,
+                                     ZEBRA_MAC_TYPE_GW);
+
+       /* Delete this neighbor entry. */
+       zvni_neigh_del(zvni, n);
+
+       /* see if the mac needs to be deleted as well*/
+       zvni_deref_ip2mac(zvni, mac, 0);
+
+       return 0;
+}
+
+static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet,
+                                          void *zvrf)
+{
+       zebra_vni_t *zvni = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan zl2_info;
+       struct interface *vlan_if = NULL;
+       struct interface *vrr_if = NULL;
+
+       /* Add primary SVI MAC*/
+       zvni = (zebra_vni_t *)backet->data;
+       if (!zvni)
+               return;
+
+       zif = zvni->vxlan_if->info;
+       zl2_info = zif->l2info.vxl;
+
+       vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+                                 zif->brslave_info.br_if);
+       if (!vlan_if)
+               return;
+
+       /* Del primary MAC-IP */
+       zvni_del_macip_for_intf(vlan_if, zvni);
+
+       /* Del VRR MAC-IP - if any*/
+       vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+       if (vrr_if)
+               zvni_del_macip_for_intf(vrr_if, zvni);
+
+       return;
+}
+
+static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
+                                          void *zvrf)
+{
+       zebra_vni_t *zvni = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan zl2_info;
+       struct interface *vlan_if = NULL;
+       struct interface *vrr_if = NULL;
+
+       zvni = (zebra_vni_t *)backet->data;
+       if (!zvni)
+               return;
+
+       if (!advertise_gw_macip_enabled(zvrf, zvni))
+               return;
+
+       zif = zvni->vxlan_if->info;
+       zl2_info = zif->l2info.vxl;
+
+       vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+                                 zif->brslave_info.br_if);
+       if (!vlan_if)
+               return;
+
+       if (!advertise_gw_macip_enabled(zvrf, zvni))
+               return;
+
+       /* Add primary 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);
+
+       return;
+}
+
 /*
  * Make hash key for MAC.
  */
@@ -864,8 +1188,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
                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->zvrf, wctx->zvni->vni,
-                                                   &mac->macaddr, sticky);
+                       zvni_mac_send_del_to_client(
+                               wctx->zvrf, wctx->zvni->vni, &mac->macaddr,
+                               (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
                }
 
                if (wctx->uninstall)
@@ -941,9 +1266,9 @@ 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(struct zebra_vrf *zvrf, vni_t vni,
-                                      struct ethaddr *macaddr, u_char sticky)
+                                      struct ethaddr *macaddr, u_char flags)
 {
-       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky,
+       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_ADD);
 }
 
@@ -951,9 +1276,9 @@ static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni,
  * Inform BGP about local MAC deletion.
  */
 static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni,
-                                      struct ethaddr *macaddr, u_char sticky)
+                                      struct ethaddr *macaddr, u_char flags)
 {
-       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky,
+       return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_DEL);
 }
 
@@ -1234,6 +1559,7 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
        struct zebra_if *zif;
        struct interface *vlan_if;
        struct zebra_l2info_vxlan *vxl;
+       struct interface *vrr_if;
 
        zif = ifp->info;
        vxl = &zif->l2info.vxl;
@@ -1247,8 +1573,20 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni,
        macfdb_read_for_bridge(zvrf->zns, ifp, zif->brslave_info.br_if);
        vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan,
                                  zif->brslave_info.br_if);
-       if (vlan_if)
+       if (vlan_if) {
+
+               if (advertise_gw_macip_enabled(zvrf, 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);
+               }
+
                neigh_read_for_vlan(zvrf->zns, vlan_if);
+       }
 }
 
 /*
@@ -1915,7 +2253,7 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
        assert(zvrf);
 
        /* Remove neighbor from BGP. */
-       zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac);
+       zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, 0);
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
@@ -2008,8 +2346,8 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
 
        /* Issue delete for older info, if needed. */
        if (send_del)
-               zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip,
-                                             &n->emac);
+               zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac,
+                                             0);
 
        /* Set "local" forwarding info. */
        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
@@ -2019,7 +2357,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
        /* Inform BGP if required. */
        if (send_upd)
                return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip,
-                                                    macaddr);
+                                                    macaddr, 0);
 
        return 0;
 }
@@ -2419,7 +2757,8 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
 
        /* Remove MAC from BGP. */
        sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky);
+       zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
+                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
 
        /* Delete this MAC entry. */
        zvni_mac_del(zvni, mac);
@@ -2526,7 +2865,8 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
 
        /* Remove MAC from BGP. */
        sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky);
+       zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr,
+                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
 
        /* Delete this MAC entry. */
        zvni_mac_del(zvni, mac);
@@ -2656,8 +2996,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
 
        /* Inform BGP if required. */
        if (add)
-               return zvni_mac_send_add_to_client(zvrf, zvni->vni, macaddr,
-                                                  sticky);
+               return zvni_mac_send_add_to_client(
+                       zvrf, zvni->vni, macaddr,
+                       (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
 
        return 0;
 }
@@ -2788,6 +3129,100 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length,
        return 0;
 }
 
+/*
+ * Add/Del gateway macip to evpn
+ * g/w can be:
+ *  1. SVI interface on a vlan aware bridge
+ *  2. SVI interface on a vlan unaware bridge
+ *  3. vrr interface (MACVLAN) associated to a SVI
+ * We advertise macip routes for an interface if it is associated to VxLan vlan
+ */
+int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
+                                int add)
+{
+       struct ipaddr ip;
+       struct ethaddr macaddr;
+       zebra_vni_t *zvni = NULL;
+       struct zebra_vrf *zvrf = NULL;
+
+       memset(&ip, 0, sizeof(struct ipaddr));
+       memset(&macaddr, 0, sizeof(struct ethaddr));
+
+       if (IS_ZEBRA_IF_MACVLAN(ifp)) {
+               struct interface *svi_if =
+                       NULL; /* SVI corresponding to the MACVLAN */
+               struct zebra_if *ifp_zif =
+                       NULL; /* Zebra daemon specific info for MACVLAN */
+               struct zebra_if *svi_if_zif =
+                       NULL; /* Zebra daemon specific info for SVI*/
+
+               ifp_zif = ifp->info;
+               if (!ifp_zif)
+                       return -1;
+
+               svi_if = ifp_zif->link;
+               if (!svi_if) {
+                       zlog_err("%u:MACVLAN %s(%u) without link information",
+                                ifp->vrf_id, ifp->name, ifp->ifindex);
+                       return -1;
+               }
+
+               if (IS_ZEBRA_IF_VLAN(svi_if)) {
+                       svi_if_zif = svi_if->info;
+                       if (svi_if_zif)
+                               zvni = zvni_map_svi(svi_if, svi_if_zif->link);
+               } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
+                       zvni = zvni_map_svi(svi_if, svi_if);
+               }
+       } else if (IS_ZEBRA_IF_VLAN(ifp)) {
+               struct zebra_if *svi_if_zif =
+                       NULL; /* Zebra daemon specific info for SVI*/
+
+               svi_if_zif = ifp->info;
+               if (svi_if_zif)
+                       zvni = zvni_map_svi(ifp, svi_if_zif->link);
+       } else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
+               zvni = zvni_map_svi(ifp, ifp);
+       }
+
+       if (!zvni)
+               return 0;
+
+       if (!zvni->vxlan_if) {
+               zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up",
+                        zvni->vni, zvni);
+               return -1;
+       }
+
+       zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+       if (!zvrf)
+               return -1;
+
+       /* check if we are advertising gw macip routes */
+       if (!advertise_gw_macip_enabled(zvrf, zvni))
+               return 0;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       if (p->family == AF_INET) {
+               ip.ipa_type = IPADDR_V4;
+               memcpy(&(ip.ipaddr_v4), &(p->u.prefix4),
+                      sizeof(struct in_addr));
+       } else if (p->family == AF_INET6) {
+               ip.ipa_type = IPADDR_V6;
+               memcpy(&(ip.ipaddr_v6), &(p->u.prefix6),
+                      sizeof(struct in6_addr));
+       }
+
+
+       if (add)
+               zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
+       else
+               zvni_gw_macip_del(ifp, zvni, &ip);
+
+       return 0;
+}
+
 /*
  * Handle SVI interface going down. At this point, this is a NOP since
  * the kernel deletes the neighbor entries on this SVI (if any).
@@ -3146,6 +3581,98 @@ int zebra_vxlan_if_add(struct interface *ifp)
        return 0;
 }
 
+/*
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
+ */
+int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock,
+                                  u_short length, struct zebra_vrf *zvrf)
+{
+       struct stream *s;
+       int advertise;
+       vni_t vni = 0;
+       zebra_vni_t *zvni = NULL;
+
+       s = client->ibuf;
+       advertise = stream_getc(s);
+       vni = stream_get3(s);
+
+       if (!vni) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("%u:EVPN gateway macip Adv %s, currently %s",
+                                  zvrf_id(zvrf),
+                                  advertise ? "enabled" : "disabled",
+                                  advertise_gw_macip_enabled(zvrf, NULL)
+                                          ? "enabled"
+                                          : "disabled");
+
+               if (zvrf->advertise_gw_macip == advertise)
+                       return 0;
+
+               zvrf->advertise_gw_macip = advertise;
+
+               if (advertise_gw_macip_enabled(zvrf, zvni))
+                       hash_iterate(zvrf->vni_table,
+                                    zvni_gw_macip_add_for_vni_hash, zvrf);
+               else
+                       hash_iterate(zvrf->vni_table,
+                                    zvni_gw_macip_del_for_vni_hash, zvrf);
+
+       } else {
+               struct zebra_if *zif = NULL;
+               struct zebra_l2info_vxlan zl2_info;
+               struct interface *vlan_if = NULL;
+               struct interface *vrr_if = NULL;
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "%u:EVPN gateway macip Adv %s on VNI %d , currently %s",
+                               zvrf_id(zvrf),
+                               advertise ? "enabled" : "disabled", vni,
+                               advertise_gw_macip_enabled(zvrf, zvni)
+                                       ? "enabled"
+                                       : "disabled");
+
+               zvni = zvni_lookup(zvrf, vni);
+               if (!zvni)
+                       return 0;
+
+               if (zvni->advertise_gw_macip == advertise)
+                       return 0;
+
+               zvni->advertise_gw_macip = advertise;
+
+               zif = zvni->vxlan_if->info;
+               zl2_info = zif->l2info.vxl;
+
+               vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan,
+                                         zif->brslave_info.br_if);
+               if (!vlan_if)
+                       return 0;
+
+               if (advertise_gw_macip_enabled(zvrf, zvni)) {
+                       /* Add primary 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);
+               } else {
+                       /* Del primary MAC-IP */
+                       zvni_del_macip_for_intf(vlan_if, zvni);
+
+                       /* Del VRR MAC-IP - if any*/
+                       vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+                       if (vrr_if)
+                               zvni_del_macip_for_intf(vrr_if, zvni);
+               }
+       }
+
+       return 0;
+}
+
+
 /*
  * Handle message from client to learn (or stop learning) about VNIs and MACs.
  * When enabled, the VNI hash table will be built and MAC FDB table read;
@@ -3174,6 +3701,10 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock,
                /* Build VNI hash table and inform BGP. */
                zvni_build_hash_table(zvrf);
 
+               /* Add all SVI (L3 GW) MACs to BGP*/
+               hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
+                            zvrf);
+
                /* Read the MAC FDB */
                macfdb_read(zvrf->zns);
 
index f9ecd8333dd2023b5e45f0b1b623a0f8afdb0b0d..dca8006033e30701002bc91447f5b722eef032c6 100644 (file)
@@ -68,6 +68,8 @@ extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                  vni_t vni);
 extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf);
 
+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);
 extern int zebra_vxlan_svi_down(struct interface *ifp,
                                struct interface *link_if);
@@ -104,6 +106,9 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock,
                                       u_short length, struct zebra_vrf *zvrf);
 extern int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock,
                                       u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock,
+                                         u_short length,
+                                         struct zebra_vrf *zvrf);
 extern int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock,
                                         u_short length,
                                         struct zebra_vrf *zvrf);
index fbde72292798a53568d196808cc82db98e86e0e0..2e5943a75c00cf862d5c97bc0921ba9b65b009a8 100644 (file)
@@ -63,6 +63,9 @@ struct zebra_vni_t_ {
        /* VNI - key */
        vni_t vni;
 
+       /* Flag for advertising gw macip */
+       u_int8_t advertise_gw_macip;
+
        /* Corresponding VxLAN interface. */
        struct interface *vxlan_if;
 
index 97f7122774887df5bae9d29b18049a1740aa3752..0f90939a0bb9da9f10cdf29fe38d215022e90131 100644 (file)
@@ -2418,6 +2418,9 @@ static int zebra_client_read(struct thread *thread)
        case ZEBRA_FEC_UNREGISTER:
                zserv_fec_unregister(client, sock, length);
                break;
+       case ZEBRA_ADVERTISE_DEFAULT_GW:
+               zebra_vxlan_advertise_gw_macip(client, sock, length, zvrf);
+               break;
        case ZEBRA_ADVERTISE_ALL_VNI:
                zebra_vxlan_advertise_all_vni(client, sock, length, zvrf);
                break;