From 1a98c08704e701740716f5bf0c51c68740e84708 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 28 Jun 2017 01:51:10 -0700 Subject: [PATCH] bgpd/zebra/lib: EVPN support for asymmetric VxLan routing 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 --- bgpd/bgp_evpn.c | 39 ++- bgpd/bgp_evpn.h | 2 +- bgpd/bgp_evpn_private.h | 3 + bgpd/bgp_evpn_vty.c | 135 +++++++- bgpd/bgp_zebra.c | 36 ++- bgpd/bgp_zebra.h | 3 + bgpd/bgpd.h | 3 + lib/log.c | 1 + lib/zclient.h | 5 + zebra/if_netlink.c | 2 + zebra/interface.h | 14 +- zebra/redistribute.c | 5 + zebra/zebra_vrf.h | 5 + zebra/zebra_vxlan.c | 603 +++++++++++++++++++++++++++++++++--- zebra/zebra_vxlan.h | 5 + zebra/zebra_vxlan_private.h | 3 + zebra/zserv.c | 3 + 17 files changed, 801 insertions(+), 66 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7a5e370bcf..ab3307a6a7 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -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; diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index f4c7e68a5d..e9b7857212 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -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); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 095dfa1b15..e6f6301405 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -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; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c3eb32b91d..b5c17cf9aa 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -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 } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5071be909e..2fc75ea5a2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -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); } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 8e55eb6d8d..11405d1c1b 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -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); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7992075af1..bfdddc69b1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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; diff --git a/lib/log.c b/lib/log.c index 5adb06d28c..522aa9e7ac 100644 --- 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), diff --git a/lib/zclient.h b/lib/zclient.h index 435d26e2f9..67da45e13f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -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); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index a46657dd2e..8064071c37 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -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. diff --git a/zebra/interface.h b/zebra/interface.h index ea72264696..970c3c5292 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -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) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index c3bbf40b3f..92da5fe0ce 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -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)) diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index eb0687bf8a..720268d360 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -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; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 523225bf36..ee9a88c66c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -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); diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index f9ecd8333d..dca8006033 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -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); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index fbde722927..2e5943a75c 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -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; diff --git a/zebra/zserv.c b/zebra/zserv.c index 97f7122774..0f90939a0b 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -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; -- 2.39.5