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 <mitesh@cumulusnetworks.com>
This commit is contained in:
Mitesh Kanjariya 2017-06-28 01:51:10 -07:00 committed by Donald Sharp
parent 8f4b98eedb
commit 1a98c08704
17 changed files with 801 additions and 66 deletions

View 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;

View 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);

View 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;

View 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
}

View 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);
}

View 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);

View 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;

View File

@ -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),

View 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);

View 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.

View 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)

View 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))

View 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;

View 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);

View 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);

View 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;

View 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;