static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint16_t cmd);
+ uint32_t seq, uint16_t cmd);
static unsigned int neigh_hash_keymake(void *p);
static int neigh_cmp(const void *p1, const void *p2);
static void *zvni_neigh_alloc(void *p);
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t flags);
+ uint8_t flags, uint32_t seq);
static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
uint8_t flags);
uint32_t flags);
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t flags);
+ uint8_t flags, uint32_t seq);
static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
uint8_t flags);
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct vty *vty;
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
+ const char *type_str;
+ const char *state_str;
+ bool flags_present = false;
ipaddr2str(&n->ip, buf2, sizeof(buf2));
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
+ type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
+ "local" : "remote";
+ state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
vty = (struct vty *)ctxt;
if (json == NULL) {
vty_out(vty, "IP: %s\n",
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- vty_out(vty, " MAC: %s",
+ vty_out(vty, " Type: %s\n", type_str);
+ vty_out(vty, " State: %s\n", state_str);
+ vty_out(vty, " MAC: %s\n",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
} else {
json_object_string_add(json, "ip", buf2);
+ json_object_string_add(json, "type", type_str);
+ json_object_string_add(json, "state", state_str);
json_object_string_add(json, "mac", buf1);
}
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
if (json == NULL) {
- vty_out(vty, " Remote VTEP: %s",
+ vty_out(vty, " Remote VTEP: %s\n",
inet_ntoa(n->r_vtep_ip));
} else
json_object_string_add(json, "remoteVtep",
inet_ntoa(n->r_vtep_ip));
}
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (!json) {
- vty_out(vty, "\n");
- vty_out(vty, " State: %s",
- IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active"
- : "Inactive");
- }
- }
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
- if (!json)
- vty_out(vty, " Default-gateway");
- else
+ if (!json) {
+ vty_out(vty, " Flags: Default-gateway");
+ flags_present = true;
+ } else
json_object_boolean_true_add(json, "defaultGateway");
}
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) {
- if (!json)
- vty_out(vty, " Router");
+ if (!json) {
+ vty_out(vty,
+ flags_present ? " ,Router" : " Flags: Router");
+ flags_present = true;
+ }
+ }
+ if (json == NULL) {
+ if (flags_present)
+ vty_out(vty, "\n");
+ vty_out(vty, " Local Seq: %u Remote Seq: %u\n",
+ n->loc_seq, n->rem_seq);
+ } else {
+ json_object_int_add(json, "localSequence", n->loc_seq);
+ json_object_int_add(json, "remoteSequence", n->rem_seq);
}
- if (json == NULL)
- vty_out(vty, "\n");
}
/*
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
struct neigh_walk_ctx *wctx = ctxt;
+ const char *state_str;
vty = wctx->vty;
json_vni = wctx->json;
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
ipaddr2str(&n->ip, buf2, sizeof(buf2));
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
- && !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) {
+ state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
+ return;
+
if (json_vni == NULL) {
- vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width,
- buf2, "local", buf1);
+ vty_out(vty, "%*s %-6s %-8s %-17s\n",
+ -wctx->addr_width, buf2, "local",
+ state_str, buf1);
} else {
json_object_string_add(json_row, "type", "local");
+ json_object_string_add(json_row, "state", state_str);
json_object_string_add(json_row, "mac", buf1);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
+ json_object_boolean_true_add(
+ json_row, "defaultGateway");
+ json_object_int_add(json_row, "localSequence",
+ n->loc_seq);
+ json_object_int_add(json_row, "remoteSequence",
+ n->rem_seq);
}
wctx->count++;
- } else {
- if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) {
- if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) {
- if (json_vni == NULL) {
- if (wctx->count == 0)
- vty_out(vty,
- "%*s %-6s %-17s %-21s\n",
- -wctx->addr_width,
- "Neighbor", "Type",
- "MAC", "Remote VTEP");
- vty_out(vty, "%*s %-6s %-17s %-21s\n",
- -wctx->addr_width, buf2,
- "remote", buf1,
- inet_ntoa(n->r_vtep_ip));
- } else {
- json_object_string_add(json_row, "type",
- "remote");
- json_object_string_add(json_row, "mac",
- buf1);
- json_object_string_add(
- json_row, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
- }
- wctx->count++;
- }
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
+ !IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))
+ return;
+
+ if (json_vni == NULL) {
+ if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
+ (wctx->count == 0))
+ vty_out(vty,
+ "%*s %-6s %-8s %-17s %-21s\n",
+ -wctx->addr_width, "Neighbor", "Type",
+ "State", "MAC", "Remote VTEP");
+ vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ -wctx->addr_width, buf2, "remote", state_str,
+ buf1, inet_ntoa(n->r_vtep_ip));
} else {
- if (json_vni == NULL) {
- vty_out(vty, "%*s %-6s %-17s %-21s\n",
- -wctx->addr_width, buf2, "remote", buf1,
- inet_ntoa(n->r_vtep_ip));
- } else {
- json_object_string_add(json_row, "type",
- "remote");
- json_object_string_add(json_row, "mac", buf1);
- json_object_string_add(json_row, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
- }
- wctx->count++;
+ json_object_string_add(json_row, "type", "remote");
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "mac", buf1);
+ json_object_string_add(json_row, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
+ json_object_boolean_true_add(json_row,
+ "defaultGateway");
+ json_object_int_add(json_row, "localSequence",
+ n->loc_seq);
+ json_object_int_add(json_row, "remoteSequence",
+ n->rem_seq);
}
+ wctx->count++;
}
if (json_vni)
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
if (json == NULL) {
- vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
- "Type", "MAC", "Remote VTEP");
+ vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ -wctx.addr_width, "IP", "Type",
+ "State", "MAC", "Remote VTEP");
}
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
json_object_int_add(json, "refCount",
rb_host_count(&zrmac->host_rb));
+ json_object_int_add(json, "localSequence", zrmac->loc_seq);
+ json_object_int_add(json, "remoteSequence", zrmac->rem_seq);
RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
json_object_array_add(
json_hosts,
vty_out(vty, " Remote-gateway Mac ");
vty_out(vty, "\n");
+ vty_out(vty, " Local Seq: %u Remote Seq: %u",
+ mac->loc_seq, mac->rem_seq);
+ vty_out(vty, "\n");
+
/* print all the associated neigh */
vty_out(vty, " Neighbors:\n");
if (!listcount(mac->neigh_list))
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
vty_out(vty, " %s %s\n",
ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- CHECK_FLAG(n->flags, ZEBRA_MAC_LOCAL)
- ? (IS_ZEBRA_NEIGH_ACTIVE(n)
- ? "Active"
- : "Inactive")
- : "");
+ (IS_ZEBRA_NEIGH_ACTIVE(n)
+ ? "Active" : "Inactive"));
}
}
if (json_mac_hdr)
json_mac = json_object_new_object();
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
- && !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) {
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
struct zebra_ns *zns;
ifindex_t ifindex;
struct interface *ifp;
vlanid_t vid;
+ if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
+ return;
+
zns = zebra_ns_lookup(NS_DEFAULT);
ifindex = mac->fwd_info.local.ifindex;
ifp = if_lookup_by_index_per_ns(zns, ifindex);
else
json_object_int_add(json_mac, "vlan", vid);
}
- if (json_mac_hdr == NULL)
+ if (json_mac_hdr == NULL) {
vty_out(vty, "\n");
- else
+ } else {
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
json_object_object_add(json_mac_hdr, buf1, json_mac);
+ }
+
wctx->count++;
+
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) {
- if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
- &wctx->r_vtep_ip)) {
- if (wctx->count == 0) {
- if (json_mac_hdr == NULL) {
- vty_out(vty, "\nVNI %u\n\n",
- wctx->zvni->vni);
- vty_out(vty,
- "%-17s %-6s %-21s %-5s\n",
- "MAC", "Type",
- "Intf/Remote VTEP",
- "VLAN");
- }
- }
- if (json_mac_hdr == NULL)
- vty_out(vty, "%-17s %-6s %-21s\n", buf1,
- "remote",
- inet_ntoa(mac->fwd_info
- .r_vtep_ip));
- else {
- json_object_string_add(json_mac, "type",
- "remote");
- json_object_string_add(
- json_mac, "remoteVtep",
- inet_ntoa(mac->fwd_info
- .r_vtep_ip));
- json_object_object_add(json_mac_hdr,
- buf1, json_mac);
- }
- wctx->count++;
+
+ if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
+ !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
+ &wctx->r_vtep_ip))
+ return;
+
+ if (json_mac_hdr == NULL) {
+ if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
+ (wctx->count == 0)) {
+ vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni);
+ vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC",
+ "Type", "Intf/Remote VTEP", "VLAN");
}
+ vty_out(vty, "%-17s %-6s %-21s\n", buf1, "remote",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
} else {
- if (json_mac_hdr == NULL)
- vty_out(vty, "%-17s %-6s %-21s\n", buf1,
- "remote",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
- else {
- json_object_string_add(json_mac, "type",
- "remote");
- json_object_string_add(
- json_mac, "remoteVtep",
+ json_object_string_add(json_mac, "type", "remote");
+ json_object_string_add(json_mac, "remoteVtep",
inet_ntoa(mac->fwd_info.r_vtep_ip));
- json_object_object_add(json_mac_hdr, buf1,
- json_mac);
- }
- wctx->count++;
+ json_object_object_add(json_mac_hdr, buf1, json_mac);
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
}
+
+ wctx->count++;
}
}
*/
static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
struct ipaddr *ip, uint8_t flags,
- uint16_t cmd)
+ uint32_t seq, uint16_t cmd)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
} else
stream_putl(s, 0); /* Just MAC. */
- stream_putc(s, flags); /* sticky mac/gateway mac */
+ if (cmd == ZEBRA_MACIP_ADD) {
+ stream_putc(s, flags); /* sticky mac/gateway mac */
+ stream_putl(s, seq); /* sequence number */
+ }
/* Write packet size. */
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Send MACIP %s flags 0x%x MAC %s IP %s L2-VNI %u to %s",
+ "Send MACIP %s flags 0x%x MAC %s IP %s seq %u L2-VNI %u to %s",
(cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)), vni,
+ ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
zebra_route_string(client->proto));
if (cmd == ZEBRA_MACIP_ADD)
return n;
}
-/* Process all neigh associated to a mac upon local mac add event */
-static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
- zebra_mac_t *zmac)
+/*
+ * Process all neighbors associated with a MAC upon the MAC being learnt
+ * locally or undergoing any other change (such as sequence number).
+ */
+static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
+ zebra_mac_t *zmac,
+ bool seq_change)
{
zebra_neigh_t *n = NULL;
struct listnode *node = NULL;
char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ seq_change ? "CHANGE" : "ADD", zvni->vni);
+
+ /* Walk all neighbors and mark any inactive local neighbors as
+ * active and/or update sequence number upon a move, and inform BGP.
+ * The action for remote neighbors is TBD.
+ * NOTE: We can't simply uninstall remote neighbors as the kernel may
+ * accidentally end up deleting a just-learnt local neighbor.
+ */
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- /* MAC is learnt locally, program all inactive neigh
- * pointing to this mac */
- if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "neigh %s (MAC %s) on L2-VNI %u is now ACTIVE",
- ipaddr2str(&n->ip, buf2,
- sizeof(buf2)),
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni);
-
+ if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change) {
ZEBRA_NEIGH_SET_ACTIVE(n);
+ n->loc_seq = zmac->loc_seq;
zvni_neigh_send_add_to_client(
- zvni->vni, &n->ip, &n->emac, n->flags);
- } else {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "neigh %s (MAC %s) on VNI %u should NOT be ACTIVE",
- ipaddr2str(&n->ip, buf2,
- sizeof(buf2)),
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni);
+ zvni->vni, &n->ip, &n->emac,
+ n->flags, n->loc_seq);
}
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- /* TODO: assume the neigh has moved too ?? */
}
}
}
-/* Process all neigh associated to a mac upon local mac del event */
+/*
+ * Process all neighbors associated with a local MAC upon the MAC being
+ * deleted.
+ */
static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
zebra_mac_t *zmac)
{
zebra_neigh_t *n = NULL;
struct listnode *node = NULL;
char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ zvni->vni);
+
+ /* Walk all local neighbors and mark as inactive and inform
+ * BGP, if needed.
+ * TBD: There is currently no handling for remote neighbors. We
+ * don't expect them to exist, if they do, do we install the MAC
+ * as a remote MAC and the neighbor as remote?
+ */
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
- ipaddr2str(&n->ip, buf2,
- sizeof(buf2)),
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni);
-
ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
&n->emac, 0);
}
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
- && IS_ZEBRA_DEBUG_VXLAN) {
- zlog_debug(
- "local MAC %s getting deleted on VNI %u has remote neigh %s",
- prefix_mac2str(&n->emac, buf, sizeof(buf)),
- zvni->vni,
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
}
}
}
-/* process all neigh associated to a mac entry upon remote mac add */
+/*
+ * Process all neighbors associated with a MAC upon the MAC being remotely
+ * learnt.
+ */
static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
zebra_mac_t *zmac)
{
zebra_neigh_t *n = NULL;
struct listnode *node = NULL;
char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ zvni->vni);
+
+ /* Walk all local neighbors and mark as inactive and inform
+ * BGP, if needed.
+ */
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
- ipaddr2str(&n->ip, buf2,
- sizeof(buf2)),
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni);
-
ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
&n->emac, 0);
}
}
}
-/* process all neigh associated to mac entry upon remote mac del */
+/*
+ * Process all neighbors associated with a remote MAC upon the MAC being
+ * deleted.
+ */
static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
zebra_mac_t *zmac)
{
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
-
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
- && IS_ZEBRA_DEBUG_VXLAN) {
- zlog_debug(
- "remote MAC %s getting deleted on VNI %u has local neigh %s",
- prefix_mac2str(&n->emac, buf, sizeof(buf)),
- zvni->vni,
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- }
- }
+ /* NOTE: Currently a NO-OP. */
}
/*
*/
static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t neigh_flags)
+ uint8_t neigh_flags,
+ uint32_t seq)
{
uint8_t flags = 0;
SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- ZEBRA_MACIP_ADD);
+ seq, ZEBRA_MACIP_ADD);
}
/*
struct ethaddr *macaddr, uint8_t flags)
{
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- ZEBRA_MACIP_DEL);
+ 0, ZEBRA_MACIP_DEL);
}
/*
flags = NTF_EXT_LEARNED;
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
flags |= NTF_ROUTER;
+ ZEBRA_NEIGH_SET_ACTIVE(n);
ret = kernel_add_neigh(vlan_if, &n->ip, &n->emac, flags);
#endif
return ret;
if (!vlan_if)
return -1;
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
return kernel_del_neigh(vlan_if, &n->ip);
}
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
+ ZEBRA_NEIGH_SET_ACTIVE(n);
/* Set Router flag (R-bit) */
if (ip->ipa_type == IPADDR_V6)
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
- zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
+ zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ n->flags, n->loc_seq);
return 0;
}
char buf2[INET6_ADDRSTRLEN];
zebra_neigh_t *n = NULL;
zebra_mac_t *zmac = NULL, *old_zmac = NULL;
+ uint32_t old_mac_seq = 0, mac_new_seq = 0;
+ bool upd_mac_seq = false;
+ bool neigh_mac_change = false;
bool check_rbit = false;
- /* create a dummy MAC if the MAC is not already present */
+ /* Check if the MAC exists. */
zmac = zvni_mac_lookup(zvni, macaddr);
if (!zmac) {
+ /* create a dummy MAC if the MAC is not already present */
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"AUTO MAC %s created for neigh %s on VNI %u",
memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
memset(&zmac->flags, 0, sizeof(uint32_t));
SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ } else {
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
+ /*
+ * We don't change the MAC to local upon a neighbor
+ * learn event, we wait for the explicit local MAC
+ * learn. However, we have to compute its sequence
+ * number in preparation for when it actually turns
+ * local.
+ */
+ upd_mac_seq = true;
+ }
}
- /* If same entry already exists, it might be a change or it might be a
- * move from remote to local.
- */
+ /* Check if the neighbor exists. */
n = zvni_neigh_lookup(zvni, ip);
- if (n) {
+ if (!n) {
+ /* New neighbor - create */
+ n = zvni_neigh_add(zvni, ip, macaddr);
+ if (!n) {
+ flog_err(
+ ZEBRA_ERR_MAC_ADD_FAILED,
+ "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, zvni->vni);
+ return -1;
+ }
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ check_rbit = true;
+ } else {
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
-
+ /* If there is no MAC change, BGP isn't interested. */
if (router_flag !=
(CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
? 1 : 0))
n->ifindex = ifp->ifindex;
} else {
- /* If the MAC has changed,
- * need to issue a delete first
- * as this means a different MACIP route.
- * Also, need to do some unlinking/relinking.
+ /* If the MAC has changed, need to issue a
+ * delete first as this means a different
+ * MACIP route. Also, need to do some
+ * unlinking/relinking. We also need to
+ * update the MAC's sequence number
+ * in different situations.
*/
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, 0);
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ zvni_neigh_send_del_to_client(
+ zvni->vni, &n->ip, &n->emac, 0);
old_zmac = zvni_mac_lookup(zvni, &n->emac);
if (old_zmac) {
- listnode_delete(old_zmac->neigh_list, n);
+ old_mac_seq =
+ CHECK_FLAG(old_zmac->flags,
+ ZEBRA_MAC_REMOTE) ?
+ old_zmac->rem_seq :
+ old_zmac->loc_seq;
+ neigh_mac_change = upd_mac_seq = true;
+ listnode_delete(
+ old_zmac->neigh_list, n);
zvni_deref_ip2mac(zvni, old_zmac, 0);
}
listnode_add_sort(zmac->neigh_list, n);
}
- } else
- /* Neighbor has moved from remote to local. */
- {
- /* If MAC has changed, do the unlink/link */
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ /*
+ * Neighbor has moved from remote to local. Its
+ * MAC could have also changed as part of the move.
+ */
if (memcmp(n->emac.octet, macaddr->octet,
ETH_ALEN) != 0) {
old_zmac = zvni_mac_lookup(zvni, &n->emac);
if (old_zmac) {
+ old_mac_seq = CHECK_FLAG(
+ old_zmac->flags,
+ ZEBRA_MAC_REMOTE) ?
+ old_zmac->rem_seq :
+ old_zmac->loc_seq;
+ neigh_mac_change = upd_mac_seq = true;
listnode_delete(old_zmac->neigh_list,
n);
zvni_deref_ip2mac(zvni, old_zmac, 0);
n->ifindex = ifp->ifindex;
check_rbit = true;
}
- } else {
- /* New neighbor - create */
- n = zvni_neigh_add(zvni, ip, macaddr);
- if (!n) {
- flog_err(
- ZEBRA_ERR_MAC_ADD_FAILED,
- "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni);
- return -1;
- }
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- check_rbit = true;
+ }
+
+ /* If MAC was previously remote, or the neighbor had a different
+ * MAC earlier, recompute the sequence number.
+ */
+ if (upd_mac_seq) {
+ uint32_t seq1, seq2;
+
+ seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ?
+ zmac->rem_seq + 1 : zmac->loc_seq;
+ seq2 = neigh_mac_change ? old_mac_seq + 1 : 0;
+ mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ?
+ MAX(seq1, seq2) : zmac->loc_seq;
}
/*Mark Router flag (R-bit) */
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
/* Before we program this in BGP, we need to check if MAC is locally
- * learnt as well
+ * learnt. If not, force neighbor to be inactive and reset its seq.
*/
if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Skipping neigh %s add to client as MAC %s is not local on VNI %u with flags 0x%x",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni, n->flags);
-
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
+ zmac->loc_seq = mac_new_seq;
return 0;
}
if (!check_rbit) {
+ return 0;
+ }
+
+ /* If the MAC's sequence number has changed, inform the MAC and all
+ * neighbors associated with the MAC to BGP, else just inform this
+ * neighbor.
+ */
+ if (upd_mac_seq && zmac->loc_seq != mac_new_seq) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Skipping neigh %s with MAC %s on VNI %u add to client as router flag is not set.",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
+ zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni, zmac->loc_seq, mac_new_seq);
+ zmac->loc_seq = mac_new_seq;
+ if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
+ zmac->flags, zmac->loc_seq))
+ return -1;
+ zvni_process_neigh_on_local_mac_change(zvni, zmac, 1);
return 0;
}
- /* Inform BGP. */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u with flags 0x%x",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni, n->flags);
ZEBRA_NEIGH_SET_ACTIVE(n);
+ n->loc_seq = zmac->loc_seq;
- return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
+ return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ n->flags, n->loc_seq);
}
static int zvni_remote_neigh_update(zebra_vni_t *zvni,
* Inform BGP about local MAC addition.
*/
static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t mac_flags)
+ uint8_t mac_flags, uint32_t seq)
{
uint8_t flags = 0;
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- ZEBRA_MACIP_ADD);
+ seq, ZEBRA_MACIP_ADD);
}
/*
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- ZEBRA_MACIP_DEL);
+ 0, ZEBRA_MACIP_DEL);
}
/*
return 0;
}
-/* Public functions */
-
-int is_l3vni_for_prefix_routes_only(vni_t vni)
+/* Process a remote MACIP add from BGP. */
+static void process_remote_macip_add(vni_t vni,
+ struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ struct ipaddr *ipaddr,
+ uint8_t flags,
+ uint32_t seq,
+ struct in_addr vtep_ip)
{
- zebra_l3vni_t *zl3vni = NULL;
-
- zl3vni = zl3vni_lookup(vni);
- if (!zl3vni)
- return 0;
-
- return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
-}
+ zebra_vni_t *zvni;
+ zebra_vtep_t *zvtep;
+ zebra_mac_t *mac, *old_mac;
+ zebra_neigh_t *n = NULL;
+ int update_mac = 0, update_neigh = 0;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
+ uint32_t tmp_seq;
+ uint8_t sticky = 0;
+ u_char remote_gw = 0;
+ uint8_t router_flag = 0;
-/* handle evpn route in vrf table */
-void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
-{
- zebra_l3vni_t *zl3vni = NULL;
- struct ipaddr ipv4_vtep;
+ /* Locate VNI hash entry - expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
+ return;
+ }
- zl3vni = zl3vni_from_vrf(vrf_id);
- if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ ifp = zvni->vxlan_if;
+ if (ifp)
+ zif = ifp->info;
+ if (!ifp ||
+ !if_is_operative(ifp) ||
+ !zif ||
+ !zif->brslave_info.br_if) {
+ zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info",
+ vni);
return;
+ }
- /*
- * add the next hop neighbor -
- * neigh to be installed is the ipv6 nexthop neigh
+ /* The remote VTEP specified should normally exist, but it is
+ * possible that when peering comes up, peer may advertise MACIP
+ * routes before advertising type-3 routes.
*/
- zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+ zvtep = zvni_vtep_find(zvni, &vtep_ip);
+ if (!zvtep) {
+ if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
+ flog_err(
+ ZEBRA_ERR_VTEP_ADD_FAILED,
+ "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
+ vni, zvni);
+ return;
+ }
- /*
- * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
- * address. Rmac is programmed against the ipv4 vtep because we only
- * support ipv4 tunnels in the h/w right now
- */
- memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
- ipv4_vtep.ipa_type = IPADDR_V4;
- if (vtep_ip->ipa_type == IPADDR_V6)
- ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
- &(ipv4_vtep.ipaddr_v4));
- else
- memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
- sizeof(struct in_addr));
+ zvni_vtep_install(zvni, &vtep_ip);
+ }
- /*
- * add the rmac - remote rmac to be installed is against the ipv4
- * nexthop address
- */
- zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
-}
+ sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ router_flag = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-/* handle evpn vrf route delete */
-void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
-{
- zebra_l3vni_t *zl3vni = NULL;
- zebra_neigh_t *nh = NULL;
- zebra_mac_t *zrmac = NULL;
+ mac = zvni_mac_lookup(zvni, macaddr);
- zl3vni = zl3vni_from_vrf(vrf_id);
- if (!zl3vni)
+ /* Ignore 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("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
+ vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
+ return;
+ }
+
+ /* 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
+ || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0)
+ != remote_gw
+ || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
+ || seq != mac->rem_seq)
+ update_mac = 1;
+
+ if (update_mac) {
+ if (!mac) {
+ mac = zvni_mac_add(zvni, macaddr);
+ if (!mac) {
+ zlog_warn(
+ "Failed to add MAC %s VNI %u Remote VTEP %s",
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ vni, inet_ntoa(vtep_ip));
+ return;
+ }
+
+ /* Is this MAC created for a MACIP? */
+ if (ipa_len)
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ } else {
+ const char *mac_type;
+
+ /* When host moves but changes its (MAC,IP)
+ * binding, BGP may install a MACIP entry that
+ * corresponds to "older" location of the host
+ * in transient situations (because {IP1,M1}
+ * is a different route from {IP1,M2}). Check
+ * the sequence number and ignore this update
+ * if appropriate.
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ tmp_seq = mac->loc_seq;
+ mac_type = "local";
+ } else {
+ tmp_seq = mac->rem_seq;
+ mac_type = "remote";
+ }
+ if (seq < tmp_seq) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u",
+ vni,
+ prefix_mac2str(macaddr,
+ buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr,
+ buf1, sizeof(buf1)) : "",
+ mac_type,
+ tmp_seq);
+ return;
+ }
+ }
+
+ /* Set "auto" and "remote" forwarding info. */
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ 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);
+
+ if (remote_gw)
+ SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+
+ zvni_process_neigh_on_remote_mac_add(zvni, mac);
+
+ /* Install the entry. */
+ zvni_mac_install(zvni, mac);
+ }
+
+ /* Update seq number. */
+ mac->rem_seq = seq;
+
+ /* If there is no IP, return after clearing AUTO flag of MAC. */
+ if (!ipa_len) {
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ return;
+ }
+
+ /* Check if the remote neighbor itself is unknown or has a
+ * change. If so, create or update and then install the entry.
+ */
+ n = zvni_neigh_lookup(zvni, ipaddr);
+ if (!n
+ || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ || (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0)
+ || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)
+ || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0)
+ != router_flag)
+ || seq != n->rem_seq)
+ update_neigh = 1;
+
+ if (update_neigh) {
+ if (!n) {
+ n = zvni_neigh_add(zvni, ipaddr, macaddr);
+ if (!n) {
+ zlog_warn(
+ "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
+ ipaddr2str(ipaddr, buf1,
+ sizeof(buf1)),
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ vni, inet_ntoa(vtep_ip));
+ return;
+ }
+
+ } else {
+ const char *n_type;
+
+ /* When host moves but changes its (MAC,IP)
+ * binding, BGP may install a MACIP entry that
+ * corresponds to "older" location of the host
+ * in transient situations (because {IP1,M1}
+ * is a different route from {IP1,M2}). Check
+ * the sequence number and ignore this update
+ * if appropriate.
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ tmp_seq = n->loc_seq;
+ n_type = "local";
+ } else {
+ tmp_seq = n->rem_seq;
+ n_type = "remote";
+ }
+ if (seq < tmp_seq) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u",
+ vni,
+ prefix_mac2str(macaddr,
+ buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr,
+ buf1, sizeof(buf1)) : "",
+ n_type,
+ tmp_seq);
+ return;
+ }
+ if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) {
+ /* MAC change, send a delete for old
+ * neigh if learnt locally.
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
+ IS_ZEBRA_NEIGH_ACTIVE(n))
+ zvni_neigh_send_del_to_client(
+ zvni->vni, &n->ip,
+ &n->emac, 0);
+
+ /* update neigh list for macs */
+ old_mac = zvni_mac_lookup(zvni, &n->emac);
+ if (old_mac) {
+ listnode_delete(old_mac->neigh_list, n);
+ zvni_deref_ip2mac(zvni, old_mac, 1);
+ }
+ listnode_add_sort(mac->neigh_list, n);
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+ }
+ }
+
+ /* Set "remote" forwarding info. */
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->r_vtep_ip = vtep_ip;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+
+ /* Set router flag (R-bit) to this Neighbor entry */
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ /* Install the entry. */
+ zvni_neigh_install(zvni, n);
+ }
+
+ /* Update seq number. */
+ n->rem_seq = seq;
+}
+
+/* Process a remote MACIP delete from BGP. */
+static void process_remote_macip_del(vni_t vni,
+ struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ struct ipaddr *ipaddr,
+ struct in_addr vtep_ip)
+{
+ zebra_vni_t *zvni;
+ zebra_mac_t *mac = NULL;
+ zebra_neigh_t *n = NULL;
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+
+ /* Locate VNI hash entry - expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni);
+ return;
+ }
+
+ ifp = zvni->vxlan_if;
+ if (ifp)
+ zif = ifp->info;
+ if (!ifp ||
+ !if_is_operative(ifp) ||
+ !zif ||
+ !zif->brslave_info.br_if) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info",
+ vni);
+ return;
+ }
+
+ /* The remote VTEP specified is normally expected to exist, but
+ * it is possible that the peer may delete the VTEP before deleting
+ * any MACs referring to the VTEP, in which case the handler (see
+ * remote_vtep_del) would have already deleted the MACs.
+ */
+ if (!zvni_vtep_find(zvni, &vtep_ip))
+ return;
+
+ mac = zvni_mac_lookup(zvni, macaddr);
+ if (ipa_len)
+ n = zvni_neigh_lookup(zvni, ipaddr);
+
+ if (n && !mac) {
+ zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni);
+ return;
+ }
+
+ /* If the remote mac or neighbor doesn't exist there is nothing
+ * more to do. Otherwise, uninstall the entry and then remove it.
+ */
+ if (!mac && !n)
+ return;
+
+ /* 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_warn(
+ "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
+ vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
+ return;
+ }
+
+ /* Uninstall remote neighbor or MAC. */
+ if (n) {
+ /* When the MAC changes for an IP, it is possible the
+ * client may update the new MAC before trying to delete the
+ * "old" neighbor (as these are two different MACIP routes).
+ * Do the delete only if the MAC matches.
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ && (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
+ zvni_neigh_uninstall(zvni, n);
+ zvni_neigh_del(zvni, n);
+ zvni_deref_ip2mac(zvni, mac, 1);
+ }
+ } else {
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ zvni_process_neigh_on_remote_mac_del(zvni, mac);
+
+ if (list_isempty(mac->neigh_list)) {
+ zvni_mac_uninstall(zvni, mac, 0);
+ zvni_mac_del(zvni, mac);
+ } else
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ }
+ }
+}
+
+
+/* Public functions */
+
+int is_l3vni_for_prefix_routes_only(vni_t vni)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni)
+ return 0;
+
+ return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
+}
+
+/* handle evpn route in vrf table */
+void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
+ struct ipaddr *vtep_ip,
+ struct prefix *host_prefix)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ struct ipaddr ipv4_vtep;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return;
+
+ /*
+ * add the next hop neighbor -
+ * neigh to be installed is the ipv6 nexthop neigh
+ */
+ zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+
+ /*
+ * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
+ * address. Rmac is programmed against the ipv4 vtep because we only
+ * support ipv4 tunnels in the h/w right now
+ */
+ memset(&ipv4_vtep, 0, sizeof(struct ipaddr));
+ ipv4_vtep.ipa_type = IPADDR_V4;
+ if (vtep_ip->ipa_type == IPADDR_V6)
+ ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
+ &(ipv4_vtep.ipaddr_v4));
+ else
+ memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
+ sizeof(struct in_addr));
+
+ /*
+ * add the rmac - remote rmac to be installed is against the ipv4
+ * nexthop address
+ */
+ zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix);
+}
+
+/* handle evpn vrf route delete */
+void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
+ struct ipaddr *vtep_ip,
+ struct prefix *host_prefix)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ zebra_neigh_t *nh = NULL;
+ zebra_mac_t *zrmac = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni)
return;
/* find the next hop entry and rmac entry */
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
- return;
}
/*
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
} else {
json_object *json_vrf = NULL;
+
json_vrf = json_object_new_object();
json_object_string_add(json_vrf, "vrf", zvrf_name(zvrf));
json_object_int_add(json_vrf, "vni", zl3vni->vni);
vty_out(vty,
"Number of ARPs (local and remote) known for this VNI: %u\n",
num_neigh);
- vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
- "Type", "MAC", "Remote VTEP");
+ vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ -wctx.addr_width, "IP", "Type",
+ "State", "MAC", "Remote VTEP");
} else
json_object_int_add(json, "numArpNd", num_neigh);
struct ethaddr macaddr;
struct ipaddr ip;
struct in_addr vtep_ip;
- zebra_vni_t *zvni;
- zebra_mac_t *mac;
- zebra_neigh_t *n;
- unsigned short l = 0, ipa_len;
+ uint16_t l = 0, ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
- struct interface *ifp = NULL;
- struct zebra_if *zif = NULL;
memset(&macaddr, 0, sizeof(struct ethaddr));
memset(&ip, 0, sizeof(struct ipaddr));
/* Message contains VNI, followed by MAC followed by IP (if any)
* followed by remote VTEP IP.
*/
- mac = NULL;
- n = NULL;
memset(&ip, 0, sizeof(ip));
STREAM_GETL(s, vni);
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s from %s",
+ "Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %s from %s",
+ vni,
prefix_mac2str(&macaddr, buf, sizeof(buf)),
- ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
inet_ntoa(vtep_ip),
zebra_route_string(client->proto));
- /* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Failed to locate VNI hash upon remote MACIP DEL, "
- "VNI %u",
- vni);
- continue;
- }
- ifp = zvni->vxlan_if;
- if (!ifp) {
- zlog_warn(
- "VNI %u hash %p doesn't have intf upon remote MACIP DEL",
- vni, zvni);
- continue;
- }
- zif = ifp->info;
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- continue;
-
- /* The remote VTEP specified is normally expected to exist, but
- * it is
- * possible that the peer may delete the VTEP before deleting
- * any MACs
- * referring to the VTEP, in which case the handler (see
- * remote_vtep_del)
- * would have already deleted the MACs.
- */
- if (!zvni_vtep_find(zvni, &vtep_ip))
- continue;
-
- mac = zvni_mac_lookup(zvni, &macaddr);
- if (ipa_len)
- n = zvni_neigh_lookup(zvni, &ip);
-
- if (n && !mac) {
- zlog_warn("Failed to locate MAC %s for neigh %s VNI %u",
- prefix_mac2str(&macaddr, buf, sizeof(buf)),
- ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
- continue;
- }
+ process_remote_macip_del(vni, &macaddr, ipa_len, &ip, vtep_ip);
- /* If the remote mac or neighbor doesn't exist there is nothing
- * more
- * to do. Otherwise, uninstall the entry and then remove it.
- */
- 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_warn(
- "%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
- * client may
- * update the new MAC before trying to delete the "old"
- * neighbor
- * (as these are two different MACIP routes). Do the
- * delete only
- * if the MAC matches.
- */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
- && (memcmp(n->emac.octet, macaddr.octet, ETH_ALEN)
- == 0)) {
- zvni_neigh_uninstall(zvni, n);
- zvni_neigh_del(zvni, n);
- zvni_deref_ip2mac(zvni, mac, 1);
- }
- } else {
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- zvni_process_neigh_on_remote_mac_del(zvni, mac);
-
- if (list_isempty(mac->neigh_list)) {
- zvni_mac_uninstall(zvni, mac, 0);
- zvni_mac_del(zvni, mac);
- } else
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- }
- }
}
stream_failure:
struct ethaddr macaddr;
struct ipaddr ip;
struct in_addr vtep_ip;
- zebra_vni_t *zvni;
- zebra_vtep_t *zvtep;
- zebra_mac_t *mac, *old_mac;
- zebra_neigh_t *n;
- unsigned short l = 0, ipa_len;
- int update_mac = 0, update_neigh = 0;
+ uint16_t l = 0, ipa_len;
+ uint8_t flags = 0;
+ uint32_t seq;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
- uint8_t sticky = 0;
- uint8_t remote_gw = 0;
- uint8_t router_flag = 0;
- uint8_t flags = 0;
- struct interface *ifp = NULL;
- struct zebra_if *zif = NULL;
memset(&macaddr, 0, sizeof(struct ethaddr));
memset(&ip, 0, sizeof(struct ipaddr));
memset(&vtep_ip, 0, sizeof(struct in_addr));
if (!EVPN_ENABLED(zvrf)) {
- zlog_warn(
- "%s: EVPN Not turned on yet we have received a remote_macip add zapi callback",
- __PRETTY_FUNCTION__);
+ zlog_warn("EVPN not enabled, ignoring remote MACIP ADD");
return;
}
/* Message contains VNI, followed by MAC followed by IP (if any)
* followed by remote VTEP IP.
*/
- update_mac = update_neigh = 0;
- mac = NULL;
- n = NULL;
memset(&ip, 0, sizeof(ip));
STREAM_GETL(s, vni);
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
/* Get flags - sticky mac and/or gateway mac */
STREAM_GETC(s, flags);
- sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- remote_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- router_flag = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
l++;
+ STREAM_GETL(s, seq);
+ l += 4;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
+ "Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s",
+ vni,
prefix_mac2str(&macaddr, buf, sizeof(buf)),
- ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
- inet_ntoa(vtep_ip), flags,
+ ipa_len ? " IP " : "",
+ ipa_len ?
+ ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
+ flags, seq, inet_ntoa(vtep_ip),
zebra_route_string(client->proto));
- /* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_warn(
- "Failed to locate VNI hash upon remote MACIP ADD, VNI %u",
- vni);
- continue;
- }
- ifp = zvni->vxlan_if;
- if (!ifp) {
- zlog_warn(
- "VNI %u hash %p doesn't have intf upon remote MACIP add",
- vni, zvni);
- continue;
- }
- zif = ifp->info;
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- continue;
-
- /* The remote VTEP specified should normally exist, but it is
- * possible
- * that when peering comes up, peer may advertise MACIP routes
- * before
- * advertising type-3 routes.
- */
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
- if (!zvtep) {
- if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
- flog_err(
- ZEBRA_ERR_VTEP_ADD_FAILED,
- "Failed to add remote VTEP, VNI %u zvni %p",
- vni, zvni);
- continue;
- }
-
- zvni_vtep_install(zvni, &vtep_ip);
- }
-
- 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
- || (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? 1 : 0)
- != remote_gw
- || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip))
- update_mac = 1;
-
- if (update_mac) {
- if (!mac) {
- mac = zvni_mac_add(zvni, &macaddr);
- if (!mac) {
- zlog_warn(
- "Failed to add MAC %s VNI %u Remote VTEP %s",
- prefix_mac2str(&macaddr, buf,
- sizeof(buf)),
- vni, inet_ntoa(vtep_ip));
- return;
- }
-
- /* Is this MAC created for a MACIP? */
- if (ipa_len)
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- }
-
- /* Set "auto" and "remote" forwarding info. */
- UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- 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);
-
- if (remote_gw)
- SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
- else
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
-
- zvni_process_neigh_on_remote_mac_add(zvni, mac);
-
- /* Install the entry. */
- zvni_mac_install(zvni, mac);
- }
-
- /* If there is no IP, continue - after clearing AUTO flag of
- * MAC. */
- if (!ipa_len) {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- continue;
- }
-
- /* Check if the remote neighbor itself is unknown or has a
- * change.
- * If so, create or update and then install the entry.
- */
- n = zvni_neigh_lookup(zvni, &ip);
- if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
- || ((CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) ? 1 : 0)
- != router_flag)
- || (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0)
- || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip))
- update_neigh = 1;
-
- if (update_neigh) {
- if (!n) {
- n = zvni_neigh_add(zvni, &ip, &macaddr);
- if (!n) {
- zlog_warn(
- "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
- ipaddr2str(&ip, buf1,
- sizeof(buf1)),
- prefix_mac2str(&macaddr, buf,
- sizeof(buf)),
- vni, inet_ntoa(vtep_ip));
- return;
- }
-
- } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr))
- != 0) {
- /* MAC change, update neigh list for old and new
- * mac */
- old_mac = zvni_mac_lookup(zvni, &n->emac);
- if (old_mac) {
- listnode_delete(old_mac->neigh_list, n);
- zvni_deref_ip2mac(zvni, old_mac, 1);
- }
- listnode_add_sort(mac->neigh_list, n);
- memcpy(&n->emac, &macaddr, ETH_ALEN);
- }
-
- /* Set "remote" forwarding info. */
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- /* TODO: Handle MAC change. */
- n->r_vtep_ip = vtep_ip;
- SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
-
- /* Set router flag (R-bit) to this Neighbor entry */
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
- else
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
-
- /* Install the entry. */
- zvni_neigh_install(zvni, n);
- }
+ process_remote_macip_add(vni, &macaddr, ipa_len, &ip,
+ flags, seq, vtep_ip);
}
stream_failure:
}
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del MAC %s intf %s(%u) VID %u -> VNI %u",
+ zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, vid, zvni->vni);
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
- /* Remove MAC from BGP. */
- 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);
+ /* Remove MAC from BGP. */
+ zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
+
/*
* If there are no neigh associated with the mac delete the mac
* else mark it as AUTO for forward reference
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
- int add = 1;
- uint8_t mac_sticky;
+ bool mac_sticky = false;
+ bool inform_client = false;
+ bool upd_neigh = false;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
return -1;
}
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u",
- sticky ? "sticky " : "",
- prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vid, zvni->vni);
-
- /* If same entry already exists, nothing to do. */
+ /* Check if we need to create or update or it is a NO-OP. */
mac = zvni_mac_lookup(zvni, macaddr);
- if (mac) {
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- mac_sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
- ? 1
- : 0;
+ if (!mac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u",
+ sticky ? "sticky " : "",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zvni->vni);
+ mac = zvni_mac_add(zvni, macaddr);
+ if (!mac) {
+ flog_err(
+ ZEBRA_ERR_MAC_ADD_FAILED,
+ "Failed to add MAC %s intf %s(%u) VID %u VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zvni->vni);
+ return -1;
+ }
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vid;
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ inform_client = true;
+
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u curFlags 0x%x",
+ sticky ? "sticky " : "",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zvni->vni,
+ mac->flags);
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ mac_sticky = true;
/*
- * return if nothing has changed.
- * inform bgp if sticky flag has changed
- * update locally and do not inform bgp if local
- * parameters like interface has changed
+ * Update any changes and if changes are relevant to
+ * BGP, note it.
*/
if (mac_sticky == sticky
&& mac->fwd_info.local.ifindex == ifp->ifindex
ifp->name, ifp->ifindex, vid,
zvni->vni);
return 0;
- } else if (mac_sticky != sticky) {
- add = 1;
- } else {
- add = 0; /* This is an update of local
- interface. */
}
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ if (mac_sticky != sticky) {
+ if (sticky)
+ SET_FLAG(mac->flags,
+ ZEBRA_MAC_STICKY);
+ else
+ UNSET_FLAG(mac->flags,
+ ZEBRA_MAC_STICKY);
+ inform_client = true;
+ }
+
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vid;
+
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+
/*
- * If we have already learned the MAC as a remote sticky
- * MAC,
- * this is a operator error and we must log a warning
+ * MAC has either moved or was "internally" created due
+ * to a neighbor learn and is now actually learnt. If
+ * it was learnt as a remote sticky MAC, this is an
+ * operator error.
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
zlog_warn(
- "MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d",
+ "MAC %s already learnt as remote sticky behind VTEP %s VNI %u",
prefix_mac2str(macaddr, buf,
sizeof(buf)),
inet_ntoa(mac->fwd_info.r_vtep_ip),
zvni->vni);
return 0;
}
- }
- }
- if (!mac) {
- mac = zvni_mac_add(zvni, macaddr);
- if (!mac) {
- flog_err(ZEBRA_ERR_MAC_ADD_FAILED,
- "Failed to add MAC %s intf %s(%u) VID %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid);
- return -1;
+ /* If an actual move, compute MAC's seq number */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
+ mac->loc_seq = MAX(mac->rem_seq + 1,
+ mac->loc_seq);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vid;
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ /*
+ * We have to inform BGP of this MAC as well as process
+ * all neighbors.
+ */
+ inform_client = true;
+ upd_neigh = true;
}
}
- /* Set "local" forwarding info. */
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- mac->fwd_info.local.ifindex = ifp->ifindex;
- 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. */
- if (add) {
- zvni_process_neigh_on_local_mac_add(zvni, mac);
- return zvni_mac_send_add_to_client(zvni->vni, macaddr,
- mac->flags);
+ if (inform_client) {
+ if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
+ mac->flags, mac->loc_seq))
+ return -1;
}
+ /* Process all neighbors associated with this MAC, if required. */
+ if (upd_neigh)
+ zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
+
return 0;
}