bgpd/zebra/lib: Add Default Gateway extended community

1. Added default gw extended community
2. code modification to handle sticky-mac/default-gw-mac as they go together
3. show command support for newly added extended community
4. State in zebra to reflect if a mac/neigh is default gateway
5. show command enhancement to refelect the same in zebra commands

Ticket: CM-17428
Review: CCR-6580
Testing: Manual

Signed-off-by: Mitesh Kanjariya <mitesh@cumulusnetworks.com>
This commit is contained in:
Mitesh Kanjariya 2017-11-13 03:19:52 -08:00 committed by mitesh
parent d6fed38109
commit ead40654de
10 changed files with 247 additions and 71 deletions

View File

@ -1876,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
attr->sticky = sticky;
/* Check if this is a Gateway MAC-IP advertisement */
attr->default_gw = bgp_attr_default_gw(attr);
/* Extract the Rmac, if any */
bgp_attr_rmac(attr, &attr->rmac);

View File

@ -162,6 +162,9 @@ struct attr {
/* Static MAC for EVPN */
u_char sticky;
/* Flag for default gateway extended community in EVPN */
u_char default_gw;
/* route tag */
route_tag_t tag;

View File

@ -134,6 +134,36 @@ void bgp_attr_rmac(struct attr *attr,
}
}
/*
* return true if attr contains default gw extended community
*/
uint8_t bgp_attr_default_gw(struct attr *attr)
{
struct ecommunity *ecom;
int i;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return 0;
/* If there is a default gw extendd community return true otherwise
* return 0 */
for (i = 0; i < ecom->size; i++) {
u_char *pnt;
u_char type, sub_type;
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
type = *pnt++;
sub_type = *pnt++;
if ((type == ECOMMUNITY_ENCODE_OPAQUE
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
return 1;
}
return 0;
}
/*
* Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0.

View File

@ -62,5 +62,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
u_char *sticky);
extern uint8_t bgp_attr_default_gw(struct attr *attr);
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */

View File

@ -690,6 +690,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
tunneltype = ntohs(tunneltype);
len = sprintf(str_buf + str_pnt, "ET:%d",
tunneltype);
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
len = sprintf(str_buf + str_pnt,
"Default Gateway");
} else
unk_ecom = 1;
} else if (type == ECOMMUNITY_ENCODE_EVPN) {

View File

@ -506,7 +506,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p,
struct in_addr remote_vtep_ip, int add,
u_char sticky)
u_char flags)
{
struct stream *s;
int ipa_len;
@ -541,18 +541,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
}
stream_put_in_addr(s, &remote_vtep_ip);
/* TX MAC sticky status */
/* TX flags - MAC sticky status and/or gateway mac */
if (add)
stream_putc(s, sticky);
stream_putc(s, flags);
stream_putw_at(s, 0, stream_get_endp(s));
if (bgp_debug_zebra(NULL))
zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s",
zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s",
add ? "ADD" : "DEL", vpn->vni,
sticky ? "sticky " : "",
prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)),
ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)),
flags,
inet_ntop(AF_INET, &remote_vtep_ip, buf2,
sizeof(buf2)));
@ -662,9 +662,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
{
struct ecommunity ecom_encap;
struct ecommunity ecom_sticky;
struct ecommunity ecom_default_gw;
struct ecommunity ecom_rmac;
struct ecommunity_val eval;
struct ecommunity_val eval_sticky;
struct ecommunity_val eval_default_gw;
struct ecommunity_val eval_rmac;
bgp_encap_types tnl_type;
struct listnode *node, *nnode;
@ -719,6 +721,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
&ecom_rmac);
}
if (attr->default_gw) {
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
encode_default_gw_extcomm(&eval_default_gw);
ecom_default_gw.size = 1;
ecom_default_gw.val = (uint8_t *)eval_default_gw.val;
attr->ecommunity = ecommunity_merge(attr->ecommunity,
&ecom_default_gw);
}
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
}
@ -776,13 +787,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
/* Install EVPN route into zebra. */
static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p,
struct in_addr remote_vtep_ip, u_char sticky)
struct in_addr remote_vtep_ip, u_char flags)
{
int ret;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
1, sticky);
1, flags);
else
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
@ -853,6 +864,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
int ret = 0;
u_char flags = 0;
/* Compute the best path. */
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
@ -870,11 +882,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
&& !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)
&& !bgp->addpath_tx_used[afi][safi]) {
if (bgp_zebra_has_route_changed(rn, old_select))
if (bgp_zebra_has_route_changed(rn, old_select)) {
if (old_select->attr->sticky)
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (old_select->attr->default_gw)
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
ret = evpn_zebra_install(bgp, vpn,
(struct prefix_evpn *)&rn->p,
old_select->attr->nexthop,
old_select->attr->sticky);
flags);
}
UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(rn);
return ret;
@ -899,9 +916,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL) {
flags = 0;
if (new_select->attr->sticky)
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (new_select->attr->default_gw)
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
new_select->attr->nexthop,
new_select->attr->sticky);
flags);
/* If an old best existed and it was a "local" route, the only
* reason
* it would be supplanted is due to MAC mobility procedures. So,
@ -931,6 +953,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
return ret;
}
/*
* Return true if the local ri for this rn is of type gateway mac
*/
static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn)
{
struct bgp_info *tmp_ri = NULL;
struct bgp_info *local_ri = NULL;
local_ri = NULL;
for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
if (tmp_ri->peer == bgp->peer_self
&& tmp_ri->type == ZEBRA_ROUTE_BGP
&& tmp_ri->sub_type == BGP_ROUTE_STATIC)
local_ri = tmp_ri;
}
if (!local_ri)
return 0;
return local_ri->attr->default_gw;
}
/*
* Return true if the local ri for this rn has sticky set
@ -1129,7 +1173,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* SVI) advertised in EVPN.
* This will ensure that local routes are preferred for g/w macs
*/
if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
u_int32_t cur_seqnum;
/* Add MM extended community to route. */
@ -1206,7 +1250,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
bgpevpn_get_rmac(vpn, &attr.rmac);
vni2label(vpn->vni, &(attr.label));
@ -1394,22 +1439,27 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
struct bgp_info *ri;
struct attr attr;
struct attr attr_sticky;
struct attr attr_def_gw;
struct attr attr_ip6;
struct attr attr_sticky_ip6;
struct attr attr_def_gw_ip6;
struct attr *attr_new;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
memset(&attr, 0, sizeof(struct attr));
memset(&attr_sticky, 0, sizeof(struct attr));
memset(&attr_def_gw, 0, sizeof(struct attr));
memset(&attr_ip6, 0, sizeof(struct attr));
memset(&attr_sticky_ip6, 0, sizeof(struct attr));
memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
/* Build path-attribute - all type-2 routes for this VNI will share the
* same path attribute.
*/
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP);
attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
@ -1419,6 +1469,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_sticky.sticky = 1;
bgpevpn_get_rmac(vpn, &attr_sticky.rmac);
attr_def_gw.nexthop = vpn->originator_ip;
attr_def_gw.mp_nexthop_global_in = vpn->originator_ip;
attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_def_gw.default_gw = 1;
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
attr_ip6.nexthop = vpn->originator_ip;
@ -1430,12 +1485,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_sticky_ip6.sticky = 1;
bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
attr_def_gw_ip6.nexthop = vpn->originator_ip;
attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_def_gw_ip6.default_gw = 1;
bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
/* Set up RT, ENCAP and sticky MAC extended community. */
build_evpn_route_extcomm(vpn, &attr, AFI_IP);
build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
/* Walk this VNI's route table and update local type-2 routes. For any
* routes updated, update corresponding entry in the global table too.
@ -1454,6 +1516,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_sticky, 0, 1,
&ri, 0);
else if (evpn_route_is_def_gw(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_def_gw, 0, 1,
&ri, 0);
else
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr, 0, 1, &ri, 0);
@ -1462,6 +1528,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_sticky_ip6, 0, 1,
&ri, 0);
else if (evpn_route_is_def_gw(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_def_gw_ip6, 0, 1,
&ri, 0);
else
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_ip6, 0, 1,
@ -1496,7 +1566,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
/* Unintern temporary. */
aspath_unintern(&attr.aspath);
aspath_unintern(&attr_ip6.aspath);
aspath_unintern(&attr_sticky.aspath);
aspath_unintern(&attr_sticky_ip6.aspath);
aspath_unintern(&attr_def_gw.aspath);
aspath_unintern(&attr_def_gw_ip6.aspath);
return 0;
}
@ -4042,12 +4116,13 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
char buf2[INET6_ADDRSTRLEN];
zlog_err(
"%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
"%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
bgp->vrf_id, vpn->vni,
CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
: "",
prefix_mac2str(mac, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)));
ipaddr2str(ip, buf2, sizeof(buf2)),
flags);
return -1;
}

View File

@ -257,6 +257,13 @@ static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
memcpy(&eval->val[2], rmac, ETH_ALEN);
}
static inline void encode_default_gw_extcomm(struct ecommunity_val *eval)
{
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW;
}
static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
struct ecommunity_val *eval)
{

View File

@ -343,8 +343,8 @@ enum zapi_route_notify_owner {
};
/* Zebra MAC types */
#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/
#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
struct zclient_options {
bool receive_notify;

View File

@ -286,6 +286,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
: "Inactive");
}
}
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
if (!json)
vty_out(vty, " Default-gateway");
else
json_object_boolean_true_add(json, "defaultGateway");
}
if (json == NULL)
vty_out(vty, "\n");
}
@ -534,6 +540,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
vty_out(vty, " Auto Mac ");
}
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
vty_out(vty, " Sticky Mac ");
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
vty_out(vty, " Default-gateway Mac ");
vty_out(vty, "\n");
/* print all the associated neigh */
vty_out(vty, " Neighbors:\n");
@ -1409,7 +1421,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
ZEBRA_NEIGH_SET_ACTIVE(n);
zvni_neigh_send_add_to_client(
zvni->vni, &n->ip, &n->emac, 0);
zvni->vni, &n->ip, &n->emac, n->flags);
} else {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@ -1519,8 +1531,14 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
*/
static int zvni_neigh_send_add_to_client(vni_t vni,
struct ipaddr *ip,
struct ethaddr *macaddr, u_char flags)
struct ethaddr *macaddr,
u_char neigh_flags)
{
u_char flags = 0;
if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
ZEBRA_MACIP_ADD);
}
@ -1729,6 +1747,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
/* Set "local" forwarding info. */
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.vid = vxl->access_vlan;
@ -1748,9 +1767,14 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
memcpy(&n->emac, macaddr, ETH_ALEN);
n->ifindex = ifp->ifindex;
/* Only advertise in BGP if the knob is enabled */
if (!advertise_gw_macip_enabled(zvni))
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP",
@ -1759,7 +1783,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
ipaddr2str(ip, buf2, sizeof(buf2)));
zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
ZEBRA_MAC_TYPE_GW);
n->flags);
return 0;
}
@ -1793,16 +1817,21 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
return -1;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP",
ifp->name, ifp->ifindex, zvni->vni,
prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)));
/* only need to delete the entry from bgp if we sent it before */
if (advertise_gw_macip_enabled(zvni)) {
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(zvni->vni, &n->ip, &n->emac,
ZEBRA_MAC_TYPE_GW);
/* Remove neighbor from BGP. */
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
ZEBRA_MACIP_TYPE_GW);
}
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
@ -1869,9 +1898,6 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
if (!zvni)
return;
if (!advertise_gw_macip_enabled(zvni))
return;
ifp = zvni->vxlan_if;
if (!ifp)
return;
@ -1985,7 +2011,6 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
{
struct mac_walk_ctx *wctx = arg;
zebra_mac_t *mac = backet->data;
u_char sticky = 0;
if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
|| ((wctx->flags & DEL_REMOTE_MAC)
@ -1995,11 +2020,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
&& IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
&wctx->r_vtep_ip))) {
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->zvni->vni, &mac->macaddr,
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
mac->flags);
}
if (wctx->uninstall)
@ -2074,8 +2097,16 @@ 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(vni_t vni,
struct ethaddr *macaddr, u_char flags)
struct ethaddr *macaddr,
u_char mac_flags)
{
u_char flags = 0;
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
ZEBRA_MACIP_ADD);
}
@ -2084,8 +2115,16 @@ static int zvni_mac_send_add_to_client(vni_t vni,
* Inform BGP about local MAC deletion.
*/
static int zvni_mac_send_del_to_client(vni_t vni,
struct ethaddr *macaddr, u_char flags)
struct ethaddr *macaddr,
u_char mac_flags)
{
u_char flags = 0;
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
ZEBRA_MACIP_DEL);
}
@ -2393,15 +2432,13 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni,
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
if (vlan_if) {
if (advertise_gw_macip_enabled(zvni)) {
/* Add SVI MAC-IP */
zvni_add_macip_for_intf(vlan_if, 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);
}
/* 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(zns, vlan_if);
}
@ -4768,7 +4805,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
zvni->vni);
ZEBRA_NEIGH_SET_ACTIVE(n);
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
}
@ -4879,6 +4916,17 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length,
if (!mac && !n)
continue;
/* Ignore the delete if this mac is a gateway mac-ip */
if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
zlog_err("%u: Ignore Del for MAC %s neigh %s on VNI %u as it is configured as a default gateway",
zvrf_id(zvrf),
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)),
vni);
continue;
}
/* Uninstall remote neighbor or MAC. */
if (n) {
/* When the MAC changes for an IP, it is possible the
@ -4936,7 +4984,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
int update_mac = 0, update_neigh = 0;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
u_char sticky;
u_char sticky = 0;
u_char flags = 0;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
@ -4973,17 +5022,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
l += IPV4_MAX_BYTELEN;
/* Get 'sticky' flag. */
STREAM_GETC(s, sticky);
/* Get flags - sticky mac and/or gateway mac */
flags = stream_getc(s);
sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
l++;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
sticky ? "sticky " : "",
"Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
inet_ntoa(vtep_ip),
inet_ntoa(vtep_ip), flags,
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
@ -5025,13 +5074,26 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
zvni_vtep_install(zvni, &vtep_ip);
}
/* First, check if the remote MAC is unknown or has a change. If
* so,
* that needs to be updated first. Note that client could
* install
* MAC and MACIP separately or just install the latter.
*/
mac = zvni_mac_lookup(zvni, &macaddr);
/* Ignore the update if the mac is already present
as a gateway mac */
if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac",
zvrf_id(zvrf),
prefix_mac2str(&macaddr,
buf, sizeof(buf)),
ipaddr2str(&ip, buf1,
sizeof(buf1)), vni);
continue;
}
/* check if the remote MAC is unknown or has a change.
* If so, that needs to be updated first. Note that client could
* install MAC and MACIP separately or just install the latter.
*/
if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|| (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
!= sticky
@ -5146,7 +5208,6 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
u_char sticky;
zif = ifp->info;
assert(zif);
@ -5178,9 +5239,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
ifp->name, ifp->ifindex, vni);
/* Remove MAC from BGP. */
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
zvni_mac_send_del_to_client(zvni->vni, macaddr,
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
/*
* If there are no neigh associated with the mac delete the mac
@ -5253,7 +5312,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
u_char sticky;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
@ -5282,9 +5340,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
return 0;
/* Remove MAC from BGP. */
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
zvni_mac_send_del_to_client(zvni->vni, macaddr,
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
@ -5423,7 +5479,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
if (add) {
zvni_process_neigh_on_local_mac_add(zvni, mac);
return zvni_mac_send_add_to_client(zvni->vni, macaddr,
sticky);
mac->flags);
}
return 0;
@ -5687,10 +5743,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
}
/* check if we are advertising gw macip routes */
if (!advertise_gw_macip_enabled(zvni))
return 0;
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
if (p->family == AF_INET) {

View File

@ -233,6 +233,7 @@ struct zebra_mac_t_ {
#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */
#define ZEBRA_MAC_DEF_GW 0x20
/* Local or remote info. */
union {
@ -314,6 +315,7 @@ struct zebra_neigh_t_ {
#define ZEBRA_NEIGH_LOCAL 0x01
#define ZEBRA_NEIGH_REMOTE 0x02
#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */
#define ZEBRA_NEIGH_DEF_GW 0x08
enum zebra_neigh_state state;