bgpd, zebra: Support for sticky MACs

Implement support for sticky (static) MACs. This includes the following:

- Recognize MAC is static (using NUD_NOARP flag) and inform BGP
- Construct MAC mobility extended community for sticky MACs as per
RFC 7432 section 15.2
- Inform to zebra that remote MAC is sticky, where appropriate
- Install sticky MACs into the kernel with the right flag
- Appropriate handling in route selection

Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
Reviewed-by:   Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by:   Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
vivek 2017-05-15 14:42:57 -07:00 committed by Donald Sharp
parent 128ea8abbd
commit c85c03c7f9
13 changed files with 186 additions and 58 deletions

View File

@ -2115,6 +2115,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
struct peer *const peer = args->peer; struct peer *const peer = args->peer;
struct attr *const attr = args->attr; struct attr *const attr = args->attr;
const bgp_size_t length = args->length; const bgp_size_t length = args->length;
u_char sticky = 0;
if (length == 0) if (length == 0)
{ {
@ -2137,7 +2138,8 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
/* Extract MAC mobility sequence number, if any. */ /* Extract MAC mobility sequence number, if any. */
attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr); attr->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr, &sticky);
attr->extra->sticky = sticky;
return BGP_ATTR_PARSE_PROCEED; return BGP_ATTR_PARSE_PROCEED;
} }

View File

@ -113,10 +113,11 @@ char *ecom_mac2str(char *ecom_mac)
* community, if present, else 0. * community, if present, else 0.
*/ */
u_int32_t u_int32_t
bgp_attr_mac_mobility_seqnum (struct attr *attr) bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky)
{ {
struct ecommunity *ecom; struct ecommunity *ecom;
int i; int i;
u_char flags = 0;
ecom = attr->extra->ecommunity; ecom = attr->extra->ecommunity;
if (!ecom || !ecom->size) if (!ecom || !ecom->size)
@ -140,7 +141,13 @@ bgp_attr_mac_mobility_seqnum (struct attr *attr)
if (!(type == ECOMMUNITY_ENCODE_EVPN && if (!(type == ECOMMUNITY_ENCODE_EVPN &&
sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY)) sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
continue; continue;
pnt++; flags = *pnt++;
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
*sticky = 1;
else
*sticky = 0;
pnt++; pnt++;
seq_num = (*pnt++ << 24); seq_num = (*pnt++ << 24);
seq_num |= (*pnt++ << 16); seq_num |= (*pnt++ << 16);

View File

@ -64,6 +64,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
struct prefix *dst); struct prefix *dst);
extern u_int32_t extern u_int32_t
bgp_attr_mac_mobility_seqnum (struct attr *attr); bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky);
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ #endif /* _QUAGGA_BGP_ATTR_EVPN_H */

View File

@ -349,7 +349,7 @@ static int
bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn, bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p, struct prefix_evpn *p,
struct in_addr remote_vtep_ip, struct in_addr remote_vtep_ip,
int add) int add, u_char sticky)
{ {
struct stream *s; struct stream *s;
int ipa_len; int ipa_len;
@ -384,11 +384,16 @@ bgp_zebra_send_remote_macip (struct bgp *bgp, struct bgpevpn *vpn,
} }
stream_put_in_addr(s, &remote_vtep_ip); stream_put_in_addr(s, &remote_vtep_ip);
/* TX MAC sticky status */
if (add)
stream_putc (s, sticky);
stream_putw_at (s, 0, stream_get_endp (s)); stream_putw_at (s, 0, stream_get_endp (s));
if (bgp_debug_zebra (NULL)) if (bgp_debug_zebra (NULL))
zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s remote VTEP %s", zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s",
add ? "ADD" : "DEL", vpn->vni, add ? "ADD" : "DEL", vpn->vni,
sticky ? "sticky " : "",
prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)), prefix_mac2str (&p->prefix.mac, buf1, sizeof(buf1)),
ipaddr2str (&p->prefix.ip, buf3, sizeof(buf3)), ipaddr2str (&p->prefix.ip, buf3, sizeof(buf3)),
inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2))); inet_ntop(AF_INET, &remote_vtep_ip, buf2, sizeof(buf2)));
@ -447,10 +452,13 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr)
{ {
struct attr_extra *attre; struct attr_extra *attre;
struct ecommunity ecom_encap; struct ecommunity ecom_encap;
struct ecommunity ecom_sticky;
struct ecommunity_val eval; struct ecommunity_val eval;
struct ecommunity_val eval_sticky;
bgp_encap_types tnl_type; bgp_encap_types tnl_type;
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct ecommunity *ecom; struct ecommunity *ecom;
u_int32_t seqnum;
attre = bgp_attr_extra_get (attr); attre = bgp_attr_extra_get (attr);
@ -468,6 +476,16 @@ build_evpn_route_extcomm (struct bgpevpn *vpn, struct attr *attr)
for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom)) for (ALL_LIST_ELEMENTS (vpn->export_rtl, node, nnode, ecom))
attre->ecommunity = ecommunity_merge (attre->ecommunity, ecom); attre->ecommunity = ecommunity_merge (attre->ecommunity, ecom);
if (attre->sticky)
{
seqnum = 0;
memset (&ecom_sticky, 0, sizeof (ecom_sticky));
encode_mac_mobility_extcomm(1, seqnum, &eval_sticky);
ecom_sticky.size = 1;
ecom_sticky.val = (u_int8_t *)eval_sticky.val;
attre->ecommunity = ecommunity_merge (attre->ecommunity, &ecom_sticky);
}
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
} }
@ -515,7 +533,6 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr)
{ {
memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE);
} }
/* Add MM to existing */ /* Add MM to existing */
else else
{ {
@ -530,12 +547,13 @@ add_mac_mobility_to_attr (u_int32_t seq_num, struct attr *attr)
/* Install EVPN route into zebra. */ /* Install EVPN route into zebra. */
static int static int
evpn_zebra_install (struct bgp *bgp, struct bgpevpn *vpn, evpn_zebra_install (struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p, struct in_addr remote_vtep_ip) struct prefix_evpn *p, struct in_addr remote_vtep_ip,
u_char sticky)
{ {
int ret; int ret;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1); ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 1, sticky);
else else
ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 1); ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 1);
@ -550,7 +568,7 @@ evpn_zebra_uninstall (struct bgp *bgp, struct bgpevpn *vpn,
int ret; int ret;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0); ret = bgp_zebra_send_remote_macip (bgp, vpn, p, remote_vtep_ip, 0, 0);
else else
ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 0); ret = bgp_zebra_send_remote_vtep (bgp, vpn, p, 0);
@ -626,7 +644,8 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn,
{ {
if (bgp_zebra_has_route_changed (rn, old_select)) if (bgp_zebra_has_route_changed (rn, old_select))
ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p, ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *)&rn->p,
old_select->attr->nexthop); old_select->attr->nexthop,
old_select->attr->extra->sticky);
UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags (rn); bgp_zebra_clear_route_change_flags (rn);
return ret; return ret;
@ -655,7 +674,8 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn,
&& new_select->sub_type == BGP_ROUTE_NORMAL) && new_select->sub_type == BGP_ROUTE_NORMAL)
{ {
ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p, ret = evpn_zebra_install (bgp, vpn, (struct prefix_evpn *) &rn->p,
new_select->attr->nexthop); new_select->attr->nexthop,
new_select->attr->extra->sticky);
/* If an old best existed and it was a "local" route, the only reason /* 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, we * it would be supplanted is due to MAC mobility procedures. So, we
* need to do an implicit delete and withdraw that route from peers. * need to do an implicit delete and withdraw that route from peers.
@ -685,6 +705,31 @@ evpn_route_select_install (struct bgp *bgp, struct bgpevpn *vpn,
return ret; return ret;
} }
/*
* Return true if the local ri for this rn has sticky set
*/
static int
evpn_route_is_sticky (struct bgp *bgp, struct bgp_node *rn)
{
struct bgp_info *tmp_ri;
struct bgp_info *local_ri;
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->extra->sticky;
}
/* /*
* Create or update EVPN route entry. This could be in the VNI route table * Create or update EVPN route entry. This could be in the VNI route table
* or the global route table. * or the global route table.
@ -699,6 +744,7 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi,
struct attr *attr_new; struct attr *attr_new;
mpls_label_t label = MPLS_INVALID_LABEL; mpls_label_t label = MPLS_INVALID_LABEL;
int route_change = 1; int route_change = 1;
u_char sticky = 0;
*ri = NULL; *ri = NULL;
@ -755,7 +801,8 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi,
attr_new = bgp_attr_intern (attr); attr_new = bgp_attr_intern (attr);
/* Extract MAC mobility sequence number, if any. */ /* Extract MAC mobility sequence number, if any. */
attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new); attr_new->extra->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr_new, &sticky);
attr_new->extra->sticky = sticky;
/* Create new route with its attribute. */ /* Create new route with its attribute. */
tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, tmp_ri = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
@ -804,7 +851,7 @@ update_evpn_route_entry (struct bgp *bgp, struct bgpevpn *vpn, afi_t afi,
*/ */
static int static int
update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn, update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p) struct prefix_evpn *p, u_char sticky)
{ {
struct bgp_node *rn; struct bgp_node *rn;
struct attr attr; struct attr attr;
@ -821,6 +868,7 @@ update_evpn_route (struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip; attr.nexthop = vpn->originator_ip;
attr.extra->mp_nexthop_global_in = vpn->originator_ip; attr.extra->mp_nexthop_global_in = vpn->originator_ip;
attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.extra->sticky = sticky;
/* Set up RT and ENCAP extended community. */ /* Set up RT and ENCAP extended community. */
build_evpn_route_extcomm (vpn, &attr); build_evpn_route_extcomm (vpn, &attr);
@ -955,22 +1003,30 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn)
struct bgp_node *rn; struct bgp_node *rn;
struct bgp_info *ri; struct bgp_info *ri;
struct attr attr; struct attr attr;
struct attr attr_sticky;
struct attr *attr_new; struct attr *attr_new;
afi = AFI_L2VPN; afi = AFI_L2VPN;
safi = SAFI_EVPN; safi = SAFI_EVPN;
memset (&attr, 0, sizeof (struct attr)); memset (&attr, 0, sizeof (struct attr));
memset (&attr_sticky, 0, sizeof (struct attr));
/* Build path-attribute - all type-2 routes for this VNI will share the /* Build path-attribute - all type-2 routes for this VNI will share the
* same path attribute. * same path attribute.
*/ */
bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
bgp_attr_default_set (&attr_sticky, BGP_ORIGIN_IGP);
attr.nexthop = vpn->originator_ip; attr.nexthop = vpn->originator_ip;
attr.extra->mp_nexthop_global_in = vpn->originator_ip; attr.extra->mp_nexthop_global_in = vpn->originator_ip;
attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_sticky.nexthop = vpn->originator_ip;
attr_sticky.extra->mp_nexthop_global_in = vpn->originator_ip;
attr_sticky.extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr_sticky.extra->sticky = 1;
/* Set up RT, ENCAP extended community. */ /* Set up RT, ENCAP and sticky MAC extended community. */
build_evpn_route_extcomm (vpn, &attr); build_evpn_route_extcomm (vpn, &attr);
build_evpn_route_extcomm (vpn, &attr_sticky);
/* Walk this VNI's route table and update local type-2 routes. For any /* Walk this VNI's route table and update local type-2 routes. For any
* routes updated, update corresponding entry in the global table too. * routes updated, update corresponding entry in the global table too.
@ -984,7 +1040,10 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn)
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue; continue;
update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri); if (evpn_route_is_sticky (bgp, rn))
update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri);
else
update_evpn_route_entry (bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri);
/* If a local route exists for this prefix, we need to update /* If a local route exists for this prefix, we need to update
* the global routing table too. * the global routing table too.
@ -1013,7 +1072,9 @@ update_all_type2_routes (struct bgp *bgp, struct bgpevpn *vpn)
/* Unintern temporary. */ /* Unintern temporary. */
aspath_unintern (&attr.aspath); aspath_unintern (&attr.aspath);
aspath_unintern (&attr_sticky.aspath);
bgp_attr_extra_free (&attr); bgp_attr_extra_free (&attr);
bgp_attr_extra_free (&attr_sticky);
return 0; return 0;
} }
@ -1134,7 +1195,7 @@ update_routes_for_vni (struct bgp *bgp, struct bgpevpn *vpn)
* locally learnt type-2 routes (MACIP) - for this VNI. * locally learnt type-2 routes (MACIP) - for this VNI.
*/ */
build_evpn_type3_prefix (&p, vpn->originator_ip); build_evpn_type3_prefix (&p, vpn->originator_ip);
ret = update_evpn_route (bgp, vpn, &p); ret = update_evpn_route (bgp, vpn, &p, 0);
if (ret) if (ret)
return ret; return ret;
@ -2299,7 +2360,8 @@ bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni,
*/ */
int int
bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip) struct ethaddr *mac, struct ipaddr *ip,
u_char sticky)
{ {
struct bgpevpn *vpn; struct bgpevpn *vpn;
struct prefix_evpn p; struct prefix_evpn p;
@ -2321,13 +2383,14 @@ bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni,
/* Create EVPN type-2 route and schedule for processing. */ /* Create EVPN type-2 route and schedule for processing. */
build_evpn_type2_prefix (&p, mac, ip); build_evpn_type2_prefix (&p, mac, ip);
if (update_evpn_route (bgp, vpn, &p)) if (update_evpn_route (bgp, vpn, &p, sticky))
{ {
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN];
zlog_err ("%u:Failed to create Type-2 route, VNI %u MAC %s IP %s", zlog_err ("%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s",
bgp->vrf_id, vpn->vni, bgp->vrf_id, vpn->vni,
sticky ? "sticky" : "",
prefix_mac2str (mac, buf, sizeof (buf)), prefix_mac2str (mac, buf, sizeof (buf)),
ipaddr2str (ip, buf2, sizeof(buf2))); ipaddr2str (ip, buf2, sizeof(buf2)));
return -1; return -1;
@ -2417,7 +2480,7 @@ bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip
/* Create EVPN type-3 route and schedule for processing. */ /* Create EVPN type-3 route and schedule for processing. */
build_evpn_type3_prefix (&p, vpn->originator_ip); build_evpn_type3_prefix (&p, vpn->originator_ip);
if (update_evpn_route (bgp, vpn, &p)) if (update_evpn_route (bgp, vpn, &p, 0))
{ {
zlog_err ("%u: Type3 route creation failure for VNI %u", zlog_err ("%u: Type3 route creation failure for VNI %u",
bgp->vrf_id, vni); bgp->vrf_id, vni);

View File

@ -41,7 +41,8 @@ bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip); struct ethaddr *mac, struct ipaddr *ip);
extern int extern int
bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni, bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip); struct ethaddr *mac, struct ipaddr *ip,
u_char sticky);
extern int extern int
bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni); bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni);
extern int extern int

View File

@ -2180,6 +2180,7 @@ bgp_zebra_process_local_macip (int command, struct zclient *zclient,
int ipa_len; int ipa_len;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN]; char buf1[INET6_ADDRSTRLEN];
u_char sticky;
memset (&ip, 0, sizeof (ip)); memset (&ip, 0, sizeof (ip));
s = zclient->ibuf; s = zclient->ibuf;
@ -2201,19 +2202,21 @@ bgp_zebra_process_local_macip (int command, struct zclient *zclient,
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6; ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6;
stream_get (&ip.ip.addr, s, ipa_len); stream_get (&ip.ip.addr, s, ipa_len);
} }
sticky = stream_getc (s);
bgp = bgp_lookup_by_vrf_id (vrf_id); bgp = bgp_lookup_by_vrf_id (vrf_id);
if (!bgp) if (!bgp)
return 0; return 0;
if (BGP_DEBUG (zebra, ZEBRA)) if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug ("%u:Recv MACIP %s MAC %s IP %s VNI %u", zlog_debug ("%u:Recv MACIP %s %sMAC %s IP %s VNI %u",
vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
sticky ? "sticky " : "",
prefix_mac2str (&mac, buf, sizeof (buf)), prefix_mac2str (&mac, buf, sizeof (buf)),
ipaddr2str (&ip, buf1, sizeof(buf1)), vni); ipaddr2str (&ip, buf1, sizeof(buf1)), vni);
if (command == ZEBRA_MACIP_ADD) if (command == ZEBRA_MACIP_ADD)
return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip); return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip, sticky);
else else
return bgp_evpn_local_macip_del (bgp, vni, &mac, &ip); return bgp_evpn_local_macip_del (bgp, vni, &mac, &ip);
} }

View File

@ -48,7 +48,8 @@ extern int kernel_add_vtep (vni_t vni, struct interface *ifp,
extern int kernel_del_vtep (vni_t vni, struct interface *ifp, extern int kernel_del_vtep (vni_t vni, struct interface *ifp,
struct in_addr *vtep_ip); struct in_addr *vtep_ip);
extern int kernel_add_mac (struct interface *ifp, vlanid_t vid, extern int kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip); struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky);
extern int kernel_del_mac (struct interface *ifp, vlanid_t vid, extern int kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local); struct ethaddr *mac, struct in_addr vtep_ip, int local);

View File

@ -1658,6 +1658,7 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char vid_buf[20]; char vid_buf[20];
char dst_buf[30]; char dst_buf[30];
u_char sticky = 0;
ndm = NLMSG_DATA (h); ndm = NLMSG_DATA (h);
@ -1738,12 +1739,15 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4)); sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4));
} }
sticky = (ndm->ndm_state & NUD_NOARP) ? 1 : 0;
if (IS_ZEBRA_DEBUG_KERNEL) if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u)%s MAC %s%s", zlog_debug ("Rx %s family %s IF %s(%u)%s %sMAC %s%s",
nl_msg_type_to_str (h->nlmsg_type), nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family), nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex, ifp->name, ndm->ndm_ifindex,
vid_present ? vid_buf : "", vid_present ? vid_buf : "",
sticky ? "sticky " : "",
prefix_mac2str (&mac, buf, sizeof (buf)), prefix_mac2str (&mac, buf, sizeof (buf)),
dst_present ? dst_buf: ""); dst_present ? dst_buf: "");
@ -1763,7 +1767,7 @@ netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
if (IS_ZEBRA_IF_VXLAN(ifp)) if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid); return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid);
return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid); return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid, sticky);
} }
/* This is a delete notification. /* This is a delete notification.
@ -1884,7 +1888,8 @@ static int
netlink_macfdb_update (struct interface *ifp, vlanid_t vid, netlink_macfdb_update (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct ethaddr *mac,
struct in_addr vtep_ip, struct in_addr vtep_ip,
int local, int cmd) int local, int cmd,
u_char sticky)
{ {
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
struct struct
@ -1923,7 +1928,10 @@ netlink_macfdb_update (struct interface *ifp, vlanid_t vid,
req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
req.ndm.ndm_state = NUD_REACHABLE; req.ndm.ndm_state = NUD_REACHABLE;
req.ndm.ndm_flags |= NTF_EXT_LEARNED; if (sticky)
req.ndm.ndm_state |= NUD_NOARP;
else
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6);
req.ndm.ndm_ifindex = ifp->ifindex; req.ndm.ndm_ifindex = ifp->ifindex;
@ -1944,11 +1952,12 @@ netlink_macfdb_update (struct interface *ifp, vlanid_t vid,
addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex); addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex);
if (IS_ZEBRA_DEBUG_KERNEL) if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Tx %s family %s IF %s(%u)%s MAC %s%s", zlog_debug ("Tx %s family %s IF %s(%u)%s %sMAC %s%s",
nl_msg_type_to_str (cmd), nl_msg_type_to_str (cmd),
nl_family_to_str (req.ndm.ndm_family), nl_family_to_str (req.ndm.ndm_family),
ifp->name, ifp->ifindex, ifp->name, ifp->ifindex,
vid_present ? vid_buf : "", vid_present ? vid_buf : "",
sticky ? "sticky " : "",
prefix_mac2str (mac, buf, sizeof (buf)), prefix_mac2str (mac, buf, sizeof (buf)),
dst_present ? dst_buf : ""); dst_present ? dst_buf : "");
@ -2243,16 +2252,17 @@ netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip,
int int
kernel_add_mac (struct interface *ifp, vlanid_t vid, kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip) struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky)
{ {
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH); return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH, sticky);
} }
int int
kernel_del_mac (struct interface *ifp, vlanid_t vid, kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local) struct ethaddr *mac, struct in_addr vtep_ip, int local)
{ {
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH); return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH, 0);
} }
int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,

View File

@ -444,7 +444,8 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
int int
kernel_add_mac (struct interface *ifp, vlanid_t vid, kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip) struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky)
{ {
return 0; return 0;
} }

View File

@ -76,7 +76,7 @@ zvni_print_hash (struct hash_backet *backet, void *ctxt);
static int static int
zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr, struct ethaddr *macaddr,
struct ipaddr *ip, struct ipaddr *ip, u_char sticky,
u_int16_t cmd); u_int16_t cmd);
static unsigned int static unsigned int
neigh_hash_keymake (void *p); neigh_hash_keymake (void *p);
@ -136,10 +136,10 @@ static zebra_mac_t *
zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *macaddr); zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *macaddr);
static int static int
zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr); struct ethaddr *macaddr, u_char sticky);
static int static int
zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr); struct ethaddr *macaddr, u_char sticky);
static zebra_vni_t * static zebra_vni_t *
zvni_map_vlan (struct interface *ifp, struct interface *br_if, vlanid_t vid); zvni_map_vlan (struct interface *ifp, struct interface *br_if, vlanid_t vid);
static int static int
@ -542,7 +542,7 @@ zvni_print_hash (struct hash_backet *backet, void *ctxt)
static int static int
zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr, struct ethaddr *macaddr,
struct ipaddr *ip, struct ipaddr *ip, u_char sticky,
u_int16_t cmd) u_int16_t cmd)
{ {
struct zserv *client; struct zserv *client;
@ -577,12 +577,15 @@ zvni_macip_send_msg_to_client (struct zebra_vrf *zvrf, vni_t vni,
else else
stream_putl (s, 0); /* Just MAC. */ stream_putl (s, 0); /* Just MAC. */
stream_putc (s, sticky); /* Sticky MAC? */
/* Write packet size. */ /* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s)); stream_putw_at (s, 0, stream_get_endp (s));
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("%u:Send MACIP %s MAC %s IP %s VNI %u to %s", zlog_debug ("%u:Send MACIP %s %sMAC %s IP %s VNI %u to %s",
zvrf_id (zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", zvrf_id (zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
sticky ? "sticky " : "",
prefix_mac2str (macaddr, buf, sizeof (buf)), prefix_mac2str (macaddr, buf, sizeof (buf)),
ipaddr2str (ip, buf2, sizeof(buf2)), vni, ipaddr2str (ip, buf2, sizeof(buf2)), vni,
zebra_route_string (client->proto)); zebra_route_string (client->proto));
@ -776,7 +779,7 @@ static int
zvni_neigh_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_neigh_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip, struct ethaddr *macaddr) struct ipaddr *ip, struct ethaddr *macaddr)
{ {
return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, 0,
ZEBRA_MACIP_ADD); ZEBRA_MACIP_ADD);
} }
@ -787,7 +790,7 @@ static int
zvni_neigh_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_neigh_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip, struct ethaddr *macaddr) struct ipaddr *ip, struct ethaddr *macaddr)
{ {
return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, ip, 0,
ZEBRA_MACIP_DEL); ZEBRA_MACIP_DEL);
} }
@ -967,6 +970,7 @@ zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg)
{ {
struct mac_walk_ctx *wctx = arg; struct mac_walk_ctx *wctx = arg;
zebra_mac_t *mac = backet->data; zebra_mac_t *mac = backet->data;
u_char sticky = 0;
if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) ||
((wctx->flags & DEL_REMOTE_MAC) && (mac->flags & ZEBRA_MAC_REMOTE)) || ((wctx->flags & DEL_REMOTE_MAC) && (mac->flags & ZEBRA_MAC_REMOTE)) ||
@ -977,8 +981,9 @@ zvni_mac_del_hash_entry (struct hash_backet *backet, void *arg)
{ {
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) 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, zvni_mac_send_del_to_client (wctx->zvrf, wctx->zvni->vni,
&mac->macaddr); &mac->macaddr, sticky);
} }
if (wctx->uninstall) if (wctx->uninstall)
@ -1058,10 +1063,10 @@ zvni_mac_lookup (zebra_vni_t *zvni, struct ethaddr *mac)
*/ */
static int static int
zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr) struct ethaddr *macaddr, u_char sticky)
{ {
return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL,
ZEBRA_MACIP_ADD); sticky, ZEBRA_MACIP_ADD);
} }
/* /*
@ -1069,10 +1074,10 @@ zvni_mac_send_add_to_client (struct zebra_vrf *zvrf, vni_t vni,
*/ */
static int static int
zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni, zvni_mac_send_del_to_client (struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr) struct ethaddr *macaddr, u_char sticky)
{ {
return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL, return zvni_macip_send_msg_to_client (zvrf, vni, macaddr, NULL,
ZEBRA_MACIP_DEL); sticky, ZEBRA_MACIP_DEL);
} }
/* /*
@ -1259,6 +1264,7 @@ zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac)
{ {
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl; struct zebra_l2info_vxlan *vxl;
u_char sticky;
if (!(mac->flags & ZEBRA_MAC_REMOTE)) if (!(mac->flags & ZEBRA_MAC_REMOTE))
return 0; return 0;
@ -1268,8 +1274,10 @@ zvni_mac_install (zebra_vni_t *zvni, zebra_mac_t *mac)
return -1; return -1;
vxl = &zif->l2info.vxl; vxl = &zif->l2info.vxl;
sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0;
return kernel_add_mac (zvni->vxlan_if, vxl->access_vlan, return kernel_add_mac (zvni->vxlan_if, vxl->access_vlan,
&mac->macaddr, mac->fwd_info.r_vtep_ip); &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky);
} }
/* /*
@ -2353,6 +2361,7 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
int update_mac = 0, update_neigh = 0; int update_mac = 0, update_neigh = 0;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN]; char buf1[INET6_ADDRSTRLEN];
u_char sticky;
assert (EVPN_ENABLED (zvrf)); assert (EVPN_ENABLED (zvrf));
@ -2380,9 +2389,14 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
vtep_ip.s_addr = stream_get_ipv4 (s); vtep_ip.s_addr = stream_get_ipv4 (s);
l += IPV4_MAX_BYTELEN; l += IPV4_MAX_BYTELEN;
/* Get 'sticky' flag. */
sticky = stream_getc(s);
l++;
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("%u:Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s from %s", zlog_debug ("%u:Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
zvrf_id (zvrf), zvrf_id (zvrf),
sticky ? "sticky " : "",
prefix_mac2str (&macaddr, buf, sizeof (buf)), prefix_mac2str (&macaddr, buf, sizeof (buf)),
ipaddr2str (&ip, buf1, sizeof (buf1)), ipaddr2str (&ip, buf1, sizeof (buf1)),
vni, inet_ntoa (vtep_ip), vni, inet_ntoa (vtep_ip),
@ -2431,6 +2445,7 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
*/ */
mac = zvni_mac_lookup (zvni, &macaddr); mac = zvni_mac_lookup (zvni, &macaddr);
if (!mac || !CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE) || if (!mac || !CHECK_FLAG (mac->flags, ZEBRA_MAC_REMOTE) ||
(CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0) != sticky ||
!IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip))
update_mac = 1; update_mac = 1;
@ -2464,6 +2479,11 @@ zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
SET_FLAG (mac->flags, ZEBRA_MAC_REMOTE); SET_FLAG (mac->flags, ZEBRA_MAC_REMOTE);
mac->fwd_info.r_vtep_ip = vtep_ip; mac->fwd_info.r_vtep_ip = vtep_ip;
if (sticky)
SET_FLAG (mac->flags, ZEBRA_MAC_STICKY);
else
UNSET_FLAG (mac->flags, ZEBRA_MAC_STICKY);
/* Install the entry. */ /* Install the entry. */
zvni_mac_install (zvni, mac); zvni_mac_install (zvni, mac);
} }
@ -2543,6 +2563,7 @@ zebra_vxlan_check_del_local_mac (struct interface *ifp,
zebra_vni_t *zvni; zebra_vni_t *zvni;
zebra_mac_t *mac; zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
u_char sticky;
zif = ifp->info; zif = ifp->info;
assert(zif); assert(zif);
@ -2577,7 +2598,8 @@ zebra_vxlan_check_del_local_mac (struct interface *ifp,
ifp->name, ifp->ifindex, vni); ifp->name, ifp->ifindex, vni);
/* Remove MAC from BGP. */ /* Remove MAC from BGP. */
zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0;
zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr, sticky);
/* Delete this MAC entry. */ /* Delete this MAC entry. */
zvni_mac_del (zvni, mac); zvni_mac_del (zvni, mac);
@ -2651,6 +2673,7 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if,
zebra_mac_t *mac; zebra_mac_t *mac;
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
u_char sticky;
/* We are interested in MACs only on ports or (port, VLAN) that /* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI. * map to a VNI.
@ -2684,7 +2707,8 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if,
assert(zvrf); assert(zvrf);
/* Remove MAC from BGP. */ /* Remove MAC from BGP. */
zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr); sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0;
zvni_mac_send_del_to_client (zvrf, zvni->vni, macaddr, sticky);
/* Delete this MAC entry. */ /* Delete this MAC entry. */
zvni_mac_del (zvni, mac); zvni_mac_del (zvni, mac);
@ -2697,13 +2721,15 @@ zebra_vxlan_local_mac_del (struct interface *ifp, struct interface *br_if,
*/ */
int int
zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if, zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid) struct ethaddr *macaddr, vlanid_t vid,
u_char sticky)
{ {
zebra_vni_t *zvni; zebra_vni_t *zvni;
zebra_mac_t *mac; zebra_mac_t *mac;
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
int add = 1; int add = 1;
u_char mac_sticky;
/* We are interested in MACs only on ports or (port, VLAN) that /* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI. * map to a VNI.
@ -2712,8 +2738,9 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if
if (!zvni) if (!zvni)
{ {
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u, could not find VNI", zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
ifp->vrf_id, ifp->vrf_id,
sticky ? "sticky " : "",
prefix_mac2str (macaddr, buf, sizeof (buf)), prefix_mac2str (macaddr, buf, sizeof (buf)),
ifp->name, ifp->ifindex, vid); ifp->name, ifp->ifindex, vid);
return 0; return 0;
@ -2727,8 +2754,9 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if
} }
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u", zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u",
ifp->vrf_id, ifp->vrf_id,
sticky ? "sticky " : "",
prefix_mac2str (macaddr, buf, sizeof (buf)), prefix_mac2str (macaddr, buf, sizeof (buf)),
ifp->name, ifp->ifindex, vid, zvni->vni); ifp->name, ifp->ifindex, vid, zvni->vni);
@ -2738,13 +2766,17 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if
{ {
if (CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL)) if (CHECK_FLAG (mac->flags, ZEBRA_MAC_LOCAL))
{ {
if (mac->fwd_info.local.ifindex == ifp->ifindex && mac_sticky = CHECK_FLAG (mac->flags, ZEBRA_MAC_STICKY) ? 1: 0;
if (mac_sticky == sticky &&
mac->fwd_info.local.ifindex == ifp->ifindex &&
mac->fwd_info.local.vid == vid) mac->fwd_info.local.vid == vid)
{ {
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("%u:Add/Update MAC %s intf %s(%u) VID %u -> VNI %u, " zlog_debug ("%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
"entry exists and has not changed ", "entry exists and has not changed ",
ifp->vrf_id, ifp->vrf_id,
sticky ? "sticky " : "",
prefix_mac2str (macaddr, buf, sizeof (buf)), prefix_mac2str (macaddr, buf, sizeof (buf)),
ifp->name, ifp->ifindex, vid, zvni->vni); ifp->name, ifp->ifindex, vid, zvni->vni);
return 0; return 0;
@ -2777,9 +2809,14 @@ zebra_vxlan_local_mac_add_update (struct interface *ifp, struct interface *br_if
mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.vid = vid; mac->fwd_info.local.vid = vid;
if (sticky)
SET_FLAG (mac->flags, ZEBRA_MAC_STICKY);
else
UNSET_FLAG (mac->flags, ZEBRA_MAC_STICKY);
/* Inform BGP if required. */ /* Inform BGP if required. */
if (add) if (add)
return zvni_mac_send_add_to_client (zvrf, zvni->vni, macaddr); return zvni_mac_send_add_to_client (zvrf, zvni->vni, macaddr, sticky);
return 0; return 0;
} }

View File

@ -80,7 +80,8 @@ extern int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf); u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_local_mac_add_update (struct interface *ifp, extern int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if, struct interface *br_if,
struct ethaddr *mac, vlanid_t vid); struct ethaddr *mac, vlanid_t vid,
u_char sticky);
extern int zebra_vxlan_local_mac_del (struct interface *ifp, extern int zebra_vxlan_local_mac_del (struct interface *ifp,
struct interface *br_if, struct interface *br_if,
struct ethaddr *mac, vlanid_t vid); struct ethaddr *mac, vlanid_t vid);

View File

@ -111,7 +111,8 @@ int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
int zebra_vxlan_local_mac_add_update (struct interface *ifp, int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if, struct interface *br_if,
struct ethaddr *mac, vlanid_t vid) struct ethaddr *mac, vlanid_t vid,
u_char sticky)
{ {
return 0; return 0;
} }

View File

@ -102,6 +102,7 @@ struct zebra_mac_t_
#define ZEBRA_MAC_LOCAL 0x01 #define ZEBRA_MAC_LOCAL 0x01
#define ZEBRA_MAC_REMOTE 0x02 #define ZEBRA_MAC_REMOTE 0x02
#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */ #define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
/* Local or remote info. */ /* Local or remote info. */
union union