summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2019-11-26 17:56:59 +0100
committerGitHub <noreply@github.com>2019-11-26 17:56:59 +0100
commitdd90b4c86a6805b421249c77264c2d9cb29205ca (patch)
tree7f1b65ab0e921073f6fb5abd6af5c4894e7a805e
parentMerge pull request #5415 from dslicenc/ipv6-ra-fast-retrans (diff)
parentbgpd: adv pip to throw warning under default vrf (diff)
downloadfrr-dd90b4c86a6805b421249c77264c2d9cb29205ca.tar.xz
frr-dd90b4c86a6805b421249c77264c2d9cb29205ca.zip
Merge pull request #4977 from chiragshah6/evpn_dev1
* evpn primary address advertisement
-rw-r--r--bgpd/bgp_evpn.c207
-rw-r--r--bgpd/bgp_evpn.h4
-rw-r--r--bgpd/bgp_evpn_private.h21
-rw-r--r--bgpd/bgp_evpn_vty.c179
-rw-r--r--bgpd/bgp_route.h4
-rw-r--r--bgpd/bgp_zebra.c21
-rw-r--r--doc/user/bgp.rst55
-rw-r--r--lib/zclient.h1
-rw-r--r--zebra/interface.c7
-rw-r--r--zebra/zebra_vxlan.c231
-rw-r--r--zebra/zebra_vxlan.h2
-rw-r--r--zebra/zebra_vxlan_private.h45
12 files changed, 741 insertions, 36 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index f3c514fb1..d9d83335d 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -494,6 +494,39 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn,
}
}
+static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn,
+ struct prefix_evpn *p,
+ struct attr *attr, uint8_t flags)
+{
+ struct bgp *bgp_vrf = vpn->bgp_vrf;
+
+ memset(&attr->rmac, 0, sizeof(struct ethaddr));
+ if (!bgp_vrf)
+ return;
+
+ if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return;
+
+ /* Copy sys (pip) RMAC and PIP IP as nexthop
+ * in case of route is self MAC-IP,
+ * advertise-pip and advertise-svi-ip features
+ * are enabled.
+ * Otherwise, for all host MAC-IP route's
+ * copy anycast RMAC.
+ */
+ if (CHECK_FLAG(flags, BGP_EVPN_MACIP_TYPE_SVI_IP)
+ && bgp_vrf->evpn_info->advertise_pip &&
+ bgp_vrf->evpn_info->is_anycast_mac) {
+ /* copy sys rmac */
+ memcpy(&attr->rmac, &bgp_vrf->evpn_info->pip_rmac,
+ ETH_ALEN);
+ attr->nexthop = bgp_vrf->evpn_info->pip_ip;
+ attr->mp_nexthop_global_in =
+ bgp_vrf->evpn_info->pip_ip;
+ } else
+ memcpy(&attr->rmac, &bgp_vrf->rmac, ETH_ALEN);
+}
+
/*
* Create RT extended community automatically from passed information:
* of the form AS:VNI.
@@ -1543,11 +1576,47 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
memset(&attr, 0, sizeof(struct attr));
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
}
- /* Set nexthop to ourselves and fill in the Router MAC. */
- attr.nexthop = bgp_vrf->originator_ip;
- attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
+
+ /* Advertise Primary IP (PIP) is enabled, send individual
+ * IP (default instance router-id) as nexthop.
+ * PIP is disabled or vrr interface is not present
+ * use anycast-IP as nexthop and anycast RMAC.
+ */
+ if (!bgp_vrf->evpn_info->advertise_pip ||
+ (!bgp_vrf->evpn_info->is_anycast_mac)) {
+ attr.nexthop = bgp_vrf->originator_ip;
+ attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
+ memcpy(&attr.rmac, &bgp_vrf->rmac, ETH_ALEN);
+ } else {
+ /* copy sys rmac */
+ memcpy(&attr.rmac, &bgp_vrf->evpn_info->pip_rmac, ETH_ALEN);
+ if (bgp_vrf->evpn_info->pip_ip.s_addr != INADDR_ANY) {
+ attr.nexthop = bgp_vrf->evpn_info->pip_ip;
+ attr.mp_nexthop_global_in = bgp_vrf->evpn_info->pip_ip;
+ } else if (bgp_vrf->evpn_info->pip_ip.s_addr == INADDR_ANY)
+ if (bgp_debug_zebra(NULL)) {
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("VRF %s evp %s advertise-pip primary ip is not configured",
+ vrf_id_to_name(bgp_vrf->vrf_id),
+ prefix2str(evp, buf1, sizeof(buf1)));
+ }
+ }
+
+ if (bgp_debug_zebra(NULL)) {
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[PREFIX_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ zlog_debug("VRF %s type-5 route evp %s RMAC %s nexthop %s",
+ vrf_id_to_name(bgp_vrf->vrf_id),
+ prefix2str(evp, buf1, sizeof(buf1)),
+ prefix_mac2str(&attr.rmac, buf, sizeof(buf)),
+ inet_ntop(AF_INET, &attr.nexthop, buf2,
+ INET_ADDRSTRLEN));
+ }
+
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
- memcpy(&attr.rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
/* Setup RT and encap extended community */
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
@@ -1652,6 +1721,9 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
memcpy(&tmp_pi->extra->label, label, sizeof(label));
tmp_pi->extra->num_labels = num_labels;
+ /* Mark route as self type-2 route */
+ if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
+ tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP;
bgp_path_info_add(rn, tmp_pi);
} else {
tmp_pi = local_pi;
@@ -1795,8 +1867,29 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
}
/* router mac is only needed for type-2 routes here. */
- if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
- bgpevpn_get_rmac(vpn, &attr.rmac);
+ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ uint8_t af_flags = 0;
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
+ SET_FLAG(af_flags, BGP_EVPN_MACIP_TYPE_SVI_IP);
+
+ bgp_evpn_get_rmac_nexthop(vpn, p, &attr, af_flags);
+
+ if (bgp_debug_zebra(NULL)) {
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("VRF %s vni %u type-2 route evp %s RMAC %s nexthop %s",
+ vpn->bgp_vrf ?
+ vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ",
+ vpn->vni,
+ prefix2str(p, buf1, sizeof(buf1)),
+ prefix_mac2str(&attr.rmac, buf,
+ sizeof(buf)),
+ inet_ntoa(attr.mp_nexthop_global_in));
+ }
+ }
+
vni2label(vpn->vni, &(attr.label));
/* Include L3 VNI related RTs and RMAC for type-2 routes, if they're
@@ -2071,7 +2164,8 @@ static int update_all_type2_routes(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;
- bgpevpn_get_rmac(vpn, &attr.rmac);
+ bgp_evpn_get_rmac_nexthop(vpn, evp, &attr,
+ tmp_pi->extra->af_flags);
if (evpn_route_is_sticky(bgp, rn))
attr.sticky = 1;
@@ -2081,6 +2175,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
attr.router_flag = 1;
}
+ if (bgp_debug_zebra(NULL)) {
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[PREFIX_STRLEN];
+
+ zlog_debug("VRF %s vni %u evp %s RMAC %s nexthop %s",
+ vpn->bgp_vrf ?
+ vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ",
+ vpn->vni,
+ prefix2str(evp, buf1, sizeof(buf1)),
+ prefix_mac2str(&attr.rmac, buf, sizeof(buf)),
+ inet_ntoa(attr.mp_nexthop_global_in));
+ }
+
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if
* using L3 VNI for type-2 routes also.
*/
@@ -2268,7 +2375,7 @@ static int bgp_evpn_vni_flood_mode_get(struct bgp *bgp,
* situations need the route in the per-VNI table as well as the global
* table to be updated (as attributes change).
*/
-static int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
+int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
{
int ret;
struct prefix_evpn p;
@@ -3527,8 +3634,14 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
* update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5
* routes
*/
-static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
+void update_advertise_vrf_routes(struct bgp *bgp_vrf)
{
+ struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
+
+ bgp_evpn = bgp_get_evpn();
+ if (!bgp_evpn)
+ return;
+
/* update all ipv4 routes */
if (advertise_type5_routes(bgp_vrf, AFI_IP))
bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
@@ -4586,6 +4699,9 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
*/
void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
{
+ struct listnode *node;
+ struct bgp *bgp_vrf;
+
if (withdraw) {
/* delete and withdraw all the type-5 routes
@@ -4600,8 +4716,34 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
(void (*)(struct hash_bucket *,
void *))withdraw_router_id_vni,
bgp);
+
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ if (bgp_vrf->evpn_info->advertise_pip &&
+ (bgp_vrf->evpn_info->pip_ip_static.s_addr
+ == INADDR_ANY))
+ bgp_vrf->evpn_info->pip_ip.s_addr
+ = INADDR_ANY;
+ }
+ }
} else {
+ /* Assign new default instance router-id */
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ if (bgp_vrf->evpn_info->advertise_pip &&
+ (bgp_vrf->evpn_info->pip_ip_static.s_addr
+ == INADDR_ANY)) {
+ bgp_vrf->evpn_info->pip_ip =
+ bgp->router_id;
+ /* advertise type-5 routes with
+ * new nexthop
+ */
+ update_advertise_vrf_routes(bgp_vrf);
+ }
+ }
+ }
+
/* advertise all routes in the vrf as type-5 routes with the new
* RD
*/
@@ -5513,9 +5655,12 @@ static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket,
bgpevpn_link_to_l3vni(vpn);
}
-int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
+int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
+ struct ethaddr *svi_rmac,
+ struct ethaddr *vrr_rmac,
struct in_addr originator_ip, int filter,
- ifindex_t svi_ifindex)
+ ifindex_t svi_ifindex,
+ bool is_anycast_mac)
{
struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
@@ -5562,10 +5707,35 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
/* associate the vrf with l3vni and related parameters */
bgp_vrf->l3vni = l3vni;
- memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr));
bgp_vrf->originator_ip = originator_ip;
bgp_vrf->l3vni_svi_ifindex = svi_ifindex;
+ bgp_vrf->evpn_info->is_anycast_mac = is_anycast_mac;
+ /* copy anycast MAC from VRR MAC */
+ memcpy(&bgp_vrf->rmac, vrr_rmac, ETH_ALEN);
+ /* copy sys RMAC from SVI MAC */
+ memcpy(&bgp_vrf->evpn_info->pip_rmac_zebra, svi_rmac, ETH_ALEN);
+ /* PIP user configured mac is not present use svi mac as sys mac */
+ if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static))
+ memcpy(&bgp_vrf->evpn_info->pip_rmac, svi_rmac, ETH_ALEN);
+
+ if (bgp_debug_zebra(NULL)) {
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
+
+ zlog_debug("VRF %s vni %u pip %s RMAC %s sys RMAC %s static RMAC %s is_anycast_mac %s",
+ vrf_id_to_name(bgp_vrf->vrf_id),
+ bgp_vrf->l3vni,
+ bgp_vrf->evpn_info->advertise_pip ? "enable"
+ : "disable",
+ prefix_mac2str(&bgp_vrf->rmac, buf, sizeof(buf)),
+ prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
+ buf1, sizeof(buf1)),
+ prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac_static,
+ buf2, sizeof(buf2)),
+ is_anycast_mac ? "Enable" : "Disable");
+ }
/* set the right filter - are we using l3vni only for prefix routes? */
if (filter)
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
@@ -5646,6 +5816,10 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
/* remove the Rmac from the BGP vrf */
memset(&bgp_vrf->rmac, 0, sizeof(struct ethaddr));
+ memset(&bgp_vrf->evpn_info->pip_rmac_zebra, 0, ETH_ALEN);
+ if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static) &&
+ !is_zero_mac(&bgp_vrf->evpn_info->pip_rmac))
+ memset(&bgp_vrf->evpn_info->pip_rmac, 0, ETH_ALEN);
/* remove default import RT or Unmap non-default import RT */
if (!list_isempty(bgp_vrf->vrf_import_rtl)) {
@@ -6005,6 +6179,15 @@ void bgp_evpn_init(struct bgp *bgp)
bgp->evpn_info->dad_freeze_time = 0;
/* Initialize zebra vxlan */
bgp_zebra_dup_addr_detection(bgp);
+ /* Enable PIP feature by default for bgp vrf instance */
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+ struct bgp *bgp_default;
+
+ bgp->evpn_info->advertise_pip = true;
+ bgp_default = bgp_get_default();
+ if (bgp_default)
+ bgp->evpn_info->pip_ip = bgp_default->router_id;
+ }
}
/* Default BUM handling is to do head-end replication. */
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 798c3e59b..b030f0a33 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -174,8 +174,9 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
uint8_t flags, uint32_t seq);
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct ethaddr *rmac,
+ struct ethaddr *vrr_rmac,
struct in_addr originator_ip, int filter,
- ifindex_t svi_ifindex);
+ ifindex_t svi_ifindex, bool is_anycast_mac);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
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,
@@ -192,5 +193,6 @@ extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);
extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx);
extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx);
+extern void update_advertise_vrf_routes(struct bgp *bgp_vrf);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index f6bde2e9f..76cf8b2cd 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -188,6 +188,16 @@ struct bgp_evpn_info {
/* EVPN enable - advertise svi macip routes */
int advertise_svi_macip;
+ /* PIP feature knob */
+ bool advertise_pip;
+ /* PIP IP (sys ip) */
+ struct in_addr pip_ip;
+ struct in_addr pip_ip_static;
+ /* PIP MAC (sys MAC) */
+ struct ethaddr pip_rmac;
+ struct ethaddr pip_rmac_static;
+ struct ethaddr pip_rmac_zebra;
+ bool is_anycast_mac;
};
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
@@ -501,6 +511,16 @@ static inline int is_es_local(struct evpnes *es)
return CHECK_FLAG(es->flags, EVPNES_LOCAL) ? 1 : 0;
}
+static inline bool bgp_evpn_is_svi_macip_enabled(struct bgpevpn *vpn)
+{
+ struct bgp *bgp_evpn = NULL;
+
+ bgp_evpn = bgp_get_evpn();
+
+ return (bgp_evpn->evpn_info->advertise_svi_macip ||
+ vpn->advertise_svi_macip);
+}
+
extern void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf,
afi_t afi, safi_t safi,
bool add);
@@ -543,4 +563,5 @@ extern struct evpnes *bgp_evpn_es_new(struct bgp *bgp, esi_t *esi,
struct ipaddr *originator_ip);
extern void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es);
extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni);
+extern int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn);
#endif /* _BGP_EVPN_PRIVATE_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 3bc834514..d316a28dc 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -364,6 +364,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
struct ecommunity *ecom;
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
+ char buf2[ETHER_ADDR_STRLEN];
json_import_rtl = json_export_rtl = 0;
@@ -382,6 +383,19 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_string_add(json, "advertiseSviMacip", "n/a");
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_NOSLASHESCAPE);
+ json_object_string_add(json, "advertisePip",
+ bgp_vrf->evpn_info->advertise_pip ?
+ "Enabled" : "Disabled");
+ json_object_string_add(json, "sysIP",
+ inet_ntop(AF_INET,
+ &bgp_vrf->evpn_info->pip_ip,
+ buf1, INET_ADDRSTRLEN));
+ json_object_string_add(json, "sysMac",
+ prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
+ buf2, sizeof(buf2)));
+ json_object_string_add(json, "rmac",
+ prefix_mac2str(&bgp_vrf->rmac,
+ buf2, sizeof(buf2)));
} else {
vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
vty_out(vty, " (known to the kernel)");
@@ -396,6 +410,17 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
inet_ntoa(bgp_vrf->originator_ip));
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
vty_out(vty, " Advertise-svi-macip : %s\n", "n/a");
+ vty_out(vty, " Advertise-pip: %s\n",
+ bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No");
+ vty_out(vty, " System-IP: %s\n",
+ inet_ntop(AF_INET, &bgp_vrf->evpn_info->pip_ip,
+ buf1, INET_ADDRSTRLEN));
+ vty_out(vty, " System-MAC: %s\n",
+ prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
+ buf2, sizeof(buf2)));
+ vty_out(vty, " Router-MAC: %s\n",
+ prefix_mac2str(&bgp_vrf->rmac,
+ buf2, sizeof(buf2)));
}
if (!json)
@@ -3650,6 +3675,139 @@ DEFUN (no_bgp_evpn_advertise_type5,
return CMD_SUCCESS;
}
+DEFPY (bgp_evpn_advertise_pip_ip_mac,
+ bgp_evpn_advertise_pip_ip_mac_cmd,
+ "[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]",
+ NO_STR
+ "evpn system primary IP\n"
+ IP_STR
+ "ip address\n"
+ MAC_STR MAC_STR MAC_STR)
+{
+ struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
+ struct bgp *bgp_evpn = NULL;
+
+ if (EVPN_ENABLED(bgp_vrf)) {
+ vty_out(vty,
+ "This command is supported under L3VNI BGP EVPN VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ bgp_evpn = bgp_get_evpn();
+
+ if (!no) {
+ /* pip is already enabled */
+ if (argc == 1 && bgp_vrf->evpn_info->advertise_pip)
+ return CMD_SUCCESS;
+
+ bgp_vrf->evpn_info->advertise_pip = true;
+ if (ip.s_addr != INADDR_ANY) {
+ /* Already configured with same IP */
+ if (IPV4_ADDR_SAME(&ip,
+ &bgp_vrf->evpn_info->pip_ip_static))
+ return CMD_SUCCESS;
+
+ bgp_vrf->evpn_info->pip_ip_static = ip;
+ bgp_vrf->evpn_info->pip_ip = ip;
+ } else {
+ bgp_vrf->evpn_info->pip_ip_static.s_addr
+ = INADDR_ANY;
+ /* default instance router-id assignemt */
+ if (bgp_evpn)
+ bgp_vrf->evpn_info->pip_ip =
+ bgp_evpn->router_id;
+ }
+ /* parse sys mac */
+ if (!is_zero_mac(&mac->eth_addr)) {
+ /* Already configured with same MAC */
+ if (memcmp(&bgp_vrf->evpn_info->pip_rmac_static,
+ &mac->eth_addr, ETH_ALEN) == 0)
+ return CMD_SUCCESS;
+
+ memcpy(&bgp_vrf->evpn_info->pip_rmac_static,
+ &mac->eth_addr, ETH_ALEN);
+ memcpy(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->evpn_info->pip_rmac_static,
+ ETH_ALEN);
+ } else {
+ /* Copy zebra sys mac */
+ if (!is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_zebra))
+ memcpy(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->evpn_info->pip_rmac_zebra,
+ ETH_ALEN);
+ }
+ } else {
+ if (argc == 2) {
+ if (!bgp_vrf->evpn_info->advertise_pip)
+ return CMD_SUCCESS;
+ /* Disable PIP feature */
+ bgp_vrf->evpn_info->advertise_pip = false;
+ /* copy anycast mac */
+ memcpy(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->rmac, ETH_ALEN);
+ } else {
+ /* remove MAC-IP option retain PIP knob. */
+ if ((ip.s_addr != INADDR_ANY) &&
+ !IPV4_ADDR_SAME(&ip,
+ &bgp_vrf->evpn_info->pip_ip_static)) {
+ vty_out(vty,
+ "%% BGP EVPN PIP IP does not match\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!is_zero_mac(&mac->eth_addr) &&
+ memcmp(&bgp_vrf->evpn_info->pip_rmac_static,
+ &mac->eth_addr, ETH_ALEN) != 0) {
+ vty_out(vty,
+ "%% BGP EVPN PIP MAC does not match\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ /* pip_rmac can carry vrr_rmac reset only if it matches
+ * with static value.
+ */
+ if (memcmp(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->evpn_info->pip_rmac_static,
+ ETH_ALEN) == 0) {
+ /* Copy zebra sys mac */
+ if (!is_zero_mac(
+ &bgp_vrf->evpn_info->pip_rmac_zebra))
+ memcpy(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->evpn_info->pip_rmac_zebra,
+ ETH_ALEN);
+ else {
+ /* copy anycast mac */
+ memcpy(&bgp_vrf->evpn_info->pip_rmac,
+ &bgp_vrf->rmac, ETH_ALEN);
+ }
+ }
+ }
+ /* reset user configured sys MAC */
+ memset(&bgp_vrf->evpn_info->pip_rmac_static, 0, ETH_ALEN);
+ /* reset user configured sys IP */
+ bgp_vrf->evpn_info->pip_ip_static.s_addr = INADDR_ANY;
+ /* Assign default PIP IP (bgp instance router-id) */
+ if (bgp_evpn)
+ bgp_vrf->evpn_info->pip_ip = bgp_evpn->router_id;
+ else
+ bgp_vrf->evpn_info->pip_ip.s_addr = INADDR_ANY;
+ }
+
+ if (is_evpn_enabled()) {
+ struct listnode *node = NULL;
+ struct bgpevpn *vpn = NULL;
+
+ update_advertise_vrf_routes(bgp_vrf);
+
+ /* Update (svi) type-2 routes */
+ for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
+ if (!bgp_evpn_is_svi_macip_enabled(vpn))
+ continue;
+ update_routes_for_vni(bgp_evpn, vpn);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
/*
* Display VNI information - for all or a specific VNI
*/
@@ -5383,6 +5541,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
{
char buf1[RD_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
if (bgp->vnihash) {
struct list *vnilist = hash_to_list(bgp->vnihash);
@@ -5457,6 +5616,25 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
vty_out(vty, " default-originate ipv6\n");
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+ if (!bgp->evpn_info->advertise_pip)
+ vty_out(vty, " no advertise-pip\n");
+ if (bgp->evpn_info->advertise_pip) {
+ if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY)
+ vty_out(vty, " advertise-pip ip %s",
+ inet_ntop(AF_INET,
+ &bgp->evpn_info->pip_ip_static,
+ buf2, INET_ADDRSTRLEN));
+ if (!is_zero_mac(&(bgp->evpn_info->pip_rmac_static))) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ vty_out(vty, " mac %s",
+ prefix_mac2str(&bgp->evpn_info->pip_rmac,
+ buf, sizeof(buf)));
+ }
+ vty_out(vty, "\n");
+ }
+ }
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
vty_out(vty, " rd %s\n",
prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
@@ -5527,6 +5705,7 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &dup_addr_detection_auto_recovery_cmd);
install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_pip_ip_mac_cmd);
/* test commands */
install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index a710873ea..b9f3f3f76 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -114,6 +114,10 @@ struct bgp_path_info_extra {
mpls_label_t label[BGP_MAX_LABELS];
uint32_t num_labels;
+ /* af specific flags */
+ uint16_t af_flags;
+#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
+
#if ENABLE_BGP_VNC
union {
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d0a732b15..790d35069 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2469,30 +2469,37 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS)
int filter = 0;
char buf[ETHER_ADDR_STRLEN];
vni_t l3vni = 0;
- struct ethaddr rmac;
+ struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} };
struct in_addr originator_ip;
struct stream *s;
ifindex_t svi_ifindex;
+ bool is_anycast_mac = false;
+ char buf1[ETHER_ADDR_STRLEN];
- memset(&rmac, 0, sizeof(struct ethaddr));
+ memset(&svi_rmac, 0, sizeof(struct ethaddr));
memset(&originator_ip, 0, sizeof(struct in_addr));
s = zclient->ibuf;
l3vni = stream_getl(s);
if (cmd == ZEBRA_L3VNI_ADD) {
- stream_get(&rmac, s, sizeof(struct ethaddr));
+ stream_get(&svi_rmac, s, sizeof(struct ethaddr));
originator_ip.s_addr = stream_get_ipv4(s);
stream_get(&filter, s, sizeof(int));
svi_ifindex = stream_getl(s);
+ stream_get(&vrr_rmac, s, sizeof(struct ethaddr));
+ is_anycast_mac = stream_getl(s);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC %s filter %s svi-if %u",
+ zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC svi-mac %s vrr-mac %s filter %s svi-if %u",
vrf_id_to_name(vrf_id), l3vni,
- prefix_mac2str(&rmac, buf, sizeof(buf)),
+ prefix_mac2str(&svi_rmac, buf, sizeof(buf)),
+ prefix_mac2str(&vrr_rmac, buf1,
+ sizeof(buf1)),
filter ? "prefix-routes-only" : "none",
svi_ifindex);
- bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip,
- filter, svi_ifindex);
+ bgp_evpn_local_l3vni_add(l3vni, vrf_id, &svi_rmac, &vrr_rmac,
+ originator_ip, filter, svi_ifindex,
+ is_anycast_mac);
} else {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx L3-VNI DEL VRF %s VNI %u",
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4b3113cf3..0741b1d61 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2056,6 +2056,61 @@ address-family:
the VPN RIB as intermediary.
+.. _bgp-evpn:
+
+Ethernet Virtual Network - EVPN
+-------------------------------
+
+.. _bgp-evpn-advertise-pip:
+
+EVPN advertise-PIP
+^^^^^^^^^^^^^^^^^^
+
+In a EVPN symmetric routing MLAG deployment, all EVPN routes advertised
+with anycast-IP as next-hop IP and anycast MAC as the Router MAC (RMAC - in
+BGP EVPN Extended-Community).
+EVPN picks up the next-hop IP from the VxLAN interface's local tunnel IP and
+the RMAC is obtained from the MAC of the L3VNI's SVI interface.
+Note: Next-hop IP is used for EVPN routes whether symmetric routing is
+deployed or not but the RMAC is only relevant for symmetric routing scenario.
+
+Current behavior is not ideal for Prefix (type-5) and self (type-2)
+routes. This is because the traffic from remote VTEPs routed sub optimally
+if they land on the system where the route does not belong.
+
+The advertise-pip feature advertises Prefix (type-5) and self (type-2)
+routes with system's individual (primary) IP as the next-hop and individual
+(system) MAC as Router-MAC (RMAC), while leaving the behavior unchanged for
+other EVPN routes.
+
+To support this feature there needs to have ability to co-exist a
+(system-MAC, system-IP) pair with a (anycast-MAC, anycast-IP) pair with the
+ability to terminate VxLAN-encapsulated packets received for either pair on
+the same L3VNI (i.e associated VLAN). This capability is need per tenant
+VRF instance.
+
+To derive the system-MAC and the anycast MAC, there needs to have a
+separate/additional MAC-VLAN interface corresponding to L3VNI’s SVI.
+The SVI interface’s MAC address can be interpreted as system-MAC
+and MAC-VLAN interface's MAC as anycast MAC.
+
+To derive system-IP and anycast-IP, the default BGP instance's router-id is used
+as system-IP and the VxLAN interface’s local tunnel IP as the anycast-IP.
+
+User has an option to configure the system-IP and/or system-MAC value if the
+auto derived value is not preferred.
+
+Note: By default, advertise-pip feature is enabled and user has an option to
+disable the feature via configuration CLI. Once the feature is disable under
+bgp vrf instance or MAC-VLAN interface is not configured, all the routes follow
+the same behavior of using same next-hop and RMAC values.
+
+.. index:: [no] advertise-pip [ip <addr> [mac <addr>]]
+.. clicmd:: [no] advertise-pip [ip <addr> [mac <addr>]]
+
+Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
+parameters.
+
.. _bgp-cisco-compatibility:
Cisco Compatibility
diff --git a/lib/zclient.h b/lib/zclient.h
index ebf3e6450..7adb294a3 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -490,6 +490,7 @@ enum zapi_iptable_notify_owner {
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */
#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */
+#define ZEBRA_MACIP_TYPE_SVI_IP 0x10 /* SVI MAC-IP */
enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
diff --git a/zebra/interface.c b/zebra/interface.c
index 64a7e9abc..20b05dfb3 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1062,7 +1062,9 @@ void if_up(struct interface *ifp)
zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_up(ifp, link_if);
- }
+ } else if (IS_ZEBRA_IF_MACVLAN(ifp))
+ zebra_vxlan_macvlan_up(ifp);
+
}
/* Interface goes down. We have to manage different behavior of based
@@ -1094,7 +1096,8 @@ void if_down(struct interface *ifp)
zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_down(ifp, link_if);
- }
+ } else if (IS_ZEBRA_IF_MACVLAN(ifp))
+ zebra_vxlan_macvlan_down(ifp);
/* Notify to the protocol daemons. */
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index e81f26bc5..086b13d67 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -118,6 +118,8 @@ static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if);
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
+static struct interface *zvni_map_to_macvlan(struct interface *br_if,
+ struct interface *svi_if);
/* l3-vni next-hop neigh related APIs */
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
@@ -1814,6 +1816,8 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
? "prefix-routes-only"
: "none");
+ vty_out(vty, " System MAC: %s\n",
+ zl3vni_sysmac2str(zl3vni, buf, sizeof(buf)));
vty_out(vty, " Router MAC: %s\n",
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
vty_out(vty, " L2 VNIs: ");
@@ -1833,6 +1837,9 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
json_object_string_add(json, "state", zl3vni_state2str(zl3vni));
json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
json_object_string_add(
+ json, "sysMac",
+ zl3vni_sysmac2str(zl3vni, buf, sizeof(buf)));
+ json_object_string_add(
json, "routerMac",
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
json_object_string_add(
@@ -2493,6 +2500,8 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
/* Set router flag (R-bit) based on local neigh entry add */
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
@@ -2813,6 +2822,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
n->flags, n->loc_seq);
} else if (advertise_svi_macip_enabled(zvni)) {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x",
@@ -3686,7 +3696,7 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
* of two cases:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
* linked to the bridge
- * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface
+ * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge interface
* itself
*/
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
@@ -3737,6 +3747,52 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
return found ? tmp_if : NULL;
}
+/* Map to MAC-VLAN interface corresponding to specified SVI interface.
+ */
+static struct interface *zvni_map_to_macvlan(struct interface *br_if,
+ struct interface *svi_if)
+{
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ int found = 0;
+
+ /* Defensive check, caller expected to invoke only with valid bridge. */
+ if (!br_if)
+ return NULL;
+
+ if (!svi_if) {
+ zlog_debug("svi_if is not passed.");
+ return NULL;
+ }
+
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
+ assert(zif);
+
+ /* Identify corresponding VLAN interface. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
+ continue;
+ zif = tmp_if->info;
+
+ if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
+ continue;
+
+ if (zif->link == svi_if) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? tmp_if : NULL;
+}
+
+
/*
* Install remote MAC into the forwarding plane.
*/
@@ -4153,6 +4209,16 @@ static void zvni_build_hash_table(void)
*/
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ /* Associate l3vni to mac-vlan and extract VRR MAC */
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s",
+ vni, zl3vni->svi_if ? zl3vni->svi_if->name
+ : "NIL",
+ zl3vni->mac_vlan_if ?
+ zl3vni->mac_vlan_if->name : "NIL");
+
if (is_l3vni_oper_up(zl3vni))
zebra_vxlan_process_l3vni_oper_up(zl3vni);
@@ -5058,6 +5124,24 @@ struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
}
+struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni)
+{
+ struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
+
+ if (!zl3vni)
+ return NULL;
+
+ if (!zl3vni->vxlan_if)
+ return NULL;
+
+ zif = zl3vni->vxlan_if->info;
+ if (!zif)
+ return NULL;
+
+ return zvni_map_to_macvlan(zif->brslave_info.br_if, zl3vni->svi_if);
+}
+
+
zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id)
{
struct zebra_vrf *zvrf = NULL;
@@ -5141,6 +5225,19 @@ static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
return zl3vni;
}
+static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac)
+{
+ if (!zl3vni)
+ return;
+
+ if (!is_l3vni_oper_up(zl3vni))
+ return;
+
+ if (zl3vni->mac_vlan_if && if_is_operative(zl3vni->mac_vlan_if))
+ memcpy(rmac->octet, zl3vni->mac_vlan_if->hw_addr, ETH_ALEN);
+}
+
/*
* Inform BGP about l3-vni.
*/
@@ -5148,35 +5245,54 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni)
{
struct stream *s = NULL;
struct zserv *client = NULL;
- struct ethaddr rmac;
+ struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} };
+ struct zebra_vrf *zvrf;
char buf[ETHER_ADDR_STRLEN];
+ char buf1[ETHER_ADDR_STRLEN];
+ bool is_anycast_mac = true;
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
if (!client)
return 0;
- /* get the rmac */
- memset(&rmac, 0, sizeof(struct ethaddr));
- zl3vni_get_rmac(zl3vni, &rmac);
+ zvrf = zebra_vrf_lookup_by_id(zl3vni->vrf_id);
+ assert(zvrf);
+
+ /* get the svi and vrr rmac values */
+ memset(&svi_rmac, 0, sizeof(struct ethaddr));
+ zl3vni_get_svi_rmac(zl3vni, &svi_rmac);
+ zl3vni_get_vrr_rmac(zl3vni, &vrr_rmac);
+
+ /* In absence of vrr mac use svi mac as anycast MAC value */
+ if (is_zero_mac(&vrr_rmac)) {
+ memcpy(&vrr_rmac, &svi_rmac, ETH_ALEN);
+ is_anycast_mac = false;
+ }
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ /* The message is used for both vni add and/or update like
+ * vrr mac is added for l3vni SVI.
+ */
zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni));
stream_putl(s, zl3vni->vni);
- stream_put(s, &rmac, sizeof(struct ethaddr));
+ stream_put(s, &svi_rmac, sizeof(struct ethaddr));
stream_put_in_addr(s, &zl3vni->local_vtep_ip);
stream_put(s, &zl3vni->filter, sizeof(int));
stream_putl(s, zl3vni->svi_if->ifindex);
+ stream_put(s, &vrr_rmac, sizeof(struct ethaddr));
+ stream_putl(s, is_anycast_mac);
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s filter %s to %s",
+ "Send L3_VNI_ADD %u VRF %s RMAC %s VRR %s local-ip %s filter %s to %s",
zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
- prefix_mac2str(&rmac, buf, sizeof(buf)),
+ prefix_mac2str(&svi_rmac, buf, sizeof(buf)),
+ prefix_mac2str(&vrr_rmac, buf1, sizeof(buf1)),
inet_ntoa(zl3vni->local_vtep_ip),
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
? "prefix-routes-only"
@@ -8464,6 +8580,78 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
}
/*
+ * Handle MAC-VLAN interface going down.
+ * L3VNI: When MAC-VLAN interface goes down,
+ * find its associated SVI and update type2/type-5 routes
+ * with SVI as RMAC
+ */
+void zebra_vxlan_macvlan_down(struct interface *ifp)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_if *zif, *link_zif;
+ struct interface *link_ifp, *link_if;
+
+ zif = ifp->info;
+ assert(zif);
+ link_ifp = zif->link;
+ if (!link_ifp) {
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_all_vrf(zif->link_ifindex);
+ zlog_debug("macvlan %s parent link is not found. Parent index %d ifp %s",
+ ifp->name, zif->link_ifindex,
+ ifp ? ifp->name : " ");
+ }
+ return;
+ }
+ link_zif = link_ifp->info;
+ assert(link_zif);
+
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ link_zif->link_ifindex);
+
+ zl3vni = zl3vni_from_svi(link_ifp, link_if);
+ if (zl3vni) {
+ zl3vni->mac_vlan_if = NULL;
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ }
+}
+
+/*
+ * Handle MAC-VLAN interface going up.
+ * L3VNI: When MAC-VLAN interface comes up,
+ * find its associated SVI and update type-2 routes
+ * with MAC-VLAN's MAC as RMAC and for type-5 routes
+ * use SVI's MAC as RMAC.
+ */
+void zebra_vxlan_macvlan_up(struct interface *ifp)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_if *zif, *link_zif;
+ struct interface *link_ifp, *link_if;
+
+ zif = ifp->info;
+ assert(zif);
+ link_ifp = zif->link;
+ link_zif = link_ifp->info;
+ assert(link_zif);
+
+ link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ link_zif->link_ifindex);
+ zl3vni = zl3vni_from_svi(link_ifp, link_if);
+ if (zl3vni) {
+ /* associate with macvlan (VRR) interface */
+ zl3vni->mac_vlan_if = ifp;
+
+ /* process oper-up */
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ }
+}
+
+/*
* Handle VxLAN interface down
*/
int zebra_vxlan_if_down(struct interface *ifp)
@@ -8543,15 +8731,18 @@ int zebra_vxlan_if_up(struct interface *ifp)
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L3-VNI %u is UP", ifp->name,
- ifp->ifindex, vni);
-
/* we need to associate with SVI, if any, we can associate with
* svi-if only after association with vxlan-intf is complete
*/
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s"
+ , ifp->name, ifp->ifindex, vni,
+ zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
+ zl3vni->mac_vlan_if ?
+ zl3vni->mac_vlan_if->name : "NIL");
if (is_l3vni_oper_up(zl3vni))
zebra_vxlan_process_l3vni_oper_up(zl3vni);
@@ -8714,6 +8905,8 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
zebra_vxlan_process_l3vni_oper_down(zl3vni);
zl3vni->svi_if = NULL;
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if =
+ zl3vni_map_to_mac_vlan_if(zl3vni);
zl3vni->local_vtep_ip = vxl->vtep_ip;
if (is_l3vni_oper_up(zl3vni))
zebra_vxlan_process_l3vni_oper_up(
@@ -8873,6 +9066,8 @@ int zebra_vxlan_if_add(struct interface *ifp)
* after association with vxlan_if is complete */
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
if (is_l3vni_oper_up(zl3vni))
zebra_vxlan_process_l3vni_oper_up(zl3vni);
} else {
@@ -9005,6 +9200,16 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
*/
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%s: l3vni %u svi_if %s mac_vlan_if %s",
+ __PRETTY_FUNCTION__, vni,
+ zl3vni->svi_if ?
+ zl3vni->svi_if->name : "NIL",
+ zl3vni->mac_vlan_if ?
+ zl3vni->mac_vlan_if->name : "NIL");
+
/* formulate l2vni list */
hash_iterate(zvrf_evpn->vni_table, zvni_add_to_l3vni_list,
zl3vni);
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index c85e932d3..b551ba8df 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -218,6 +218,8 @@ extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx);
extern void zebra_evpn_init(void);
+extern void zebra_vxlan_macvlan_up(struct interface *ifp);
+extern void zebra_vxlan_macvlan_down(struct interface *ifp);
#ifdef __cplusplus
}
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index 8e7804264..989ea464e 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -125,6 +125,8 @@ struct zebra_l3vni_t_ {
/* SVI interface corresponding to the l3vni */
struct interface *svi_if;
+ struct interface *mac_vlan_if;
+
/* list of L2 VNIs associated with the L3 VNI */
struct list *l2vnis;
@@ -167,6 +169,44 @@ static inline const char *zl3vni_rmac2str(zebra_l3vni_t *zl3vni, char *buf,
ptr = buf;
}
+ if (zl3vni->mac_vlan_if)
+ snprintf(ptr, (ETHER_ADDR_STRLEN),
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[0],
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[1],
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[2],
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[3],
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[4],
+ (uint8_t)zl3vni->mac_vlan_if->hw_addr[5]);
+ else if (zl3vni->svi_if)
+ snprintf(ptr, (ETHER_ADDR_STRLEN),
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ (uint8_t)zl3vni->svi_if->hw_addr[0],
+ (uint8_t)zl3vni->svi_if->hw_addr[1],
+ (uint8_t)zl3vni->svi_if->hw_addr[2],
+ (uint8_t)zl3vni->svi_if->hw_addr[3],
+ (uint8_t)zl3vni->svi_if->hw_addr[4],
+ (uint8_t)zl3vni->svi_if->hw_addr[5]);
+ else
+ snprintf(ptr, ETHER_ADDR_STRLEN, "None");
+
+ return ptr;
+}
+
+/* get the sys mac string */
+static inline const char *zl3vni_sysmac2str(zebra_l3vni_t *zl3vni, char *buf,
+ int size)
+{
+ char *ptr;
+
+ if (!buf)
+ ptr = (char *)XMALLOC(MTYPE_TMP,
+ ETHER_ADDR_STRLEN * sizeof(char));
+ else {
+ assert(size >= ETHER_ADDR_STRLEN);
+ ptr = buf;
+ }
+
if (zl3vni->svi_if)
snprintf(ptr, (ETHER_ADDR_STRLEN),
"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -215,7 +255,8 @@ static inline vrf_id_t zl3vni_vrf_id(zebra_l3vni_t *zl3vni)
return zl3vni->vrf_id;
}
-static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
+static inline void zl3vni_get_svi_rmac(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac)
{
if (!zl3vni)
return;
@@ -363,6 +404,7 @@ struct zebra_neigh_t_ {
#define ZEBRA_NEIGH_DEF_GW 0x08
#define ZEBRA_NEIGH_ROUTER_FLAG 0x10
#define ZEBRA_NEIGH_DUPLICATE 0x20
+#define ZEBRA_NEIGH_SVI_IP 0x40
enum zebra_neigh_state state;
@@ -433,6 +475,7 @@ struct nh_walk_ctx {
extern zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id);
extern struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
extern struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
+extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni);
DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
bool delete, const char *reason), (rmac, zl3vni, delete, reason))