mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 10:08:41 +00:00
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:
parent
8f4b98eedb
commit
1a98c08704
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user