#include <linux/neighbour.h>
#endif
+#include "zebra/zebra_router.h"
#include "zebra/debug.h"
#include "zebra/interface.h"
#include "zebra/rib.h"
json_object *json);
static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
json_object *json);
-static void zvni_print_mac(zebra_mac_t *mac, void *ctxt);
+static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt);
static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt);
static void zvni_print(zebra_vni_t *zvni, void **ctxt);
struct ipaddr *ip, uint8_t flags,
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_add(zebra_vni_t *zvni, struct ipaddr *ip,
struct ethaddr *mac);
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
static unsigned int mac_hash_keymake(void *p);
-static int mac_cmp(const void *p1, const void *p2);
+static bool mac_cmp(const void *p1, const void *p2);
static void *zvni_mac_alloc(void *p);
static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr);
static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac);
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, uint32_t seq);
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t flags);
+static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr);
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid);
static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac);
static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt);
static unsigned int vni_hash_keymake(void *p);
-static int vni_hash_cmp(const void *p1, const void *p2);
static void *zvni_alloc(void *p);
static zebra_vni_t *zvni_lookup(vni_t vni);
static zebra_vni_t *zvni_add(vni_t vni);
struct ipaddr *ip);
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
-static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
- int uninstall);
+static int remote_neigh_count(zebra_mac_t *zmac);
+static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac);
/* Private functions */
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
/*
* Print a specific MAC entry.
*/
-static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
+static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
{
struct vty *vty;
zebra_neigh_t *n = NULL;
char buf2[INET6_ADDRSTRLEN];
vty = (struct vty *)ctxt;
- vty_out(vty, "MAC: %s",
- prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)));
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct zebra_ns *zns;
- struct interface *ifp;
- ifindex_t ifindex;
+ prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
- ifindex = mac->fwd_info.local.ifindex;
- zns = zebra_ns_lookup(NS_DEFAULT);
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (!ifp) // unexpected
- return;
- vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
- if (mac->fwd_info.local.vid)
- vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid);
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- vty_out(vty, " Remote VTEP: %s",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
- vty_out(vty, " Auto Mac ");
- }
+ if (json) {
+ json_object *json_mac = json_object_new_object();
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
- vty_out(vty, " Sticky Mac ");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ ifindex_t ifindex;
+
+ ifindex = mac->fwd_info.local.ifindex;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ if (!ifp)
+ return;
+ json_object_string_add(json_mac, "type", "local");
+ json_object_string_add(json_mac, "intf", ifp->name);
+ json_object_int_add(json_mac, "ifindex", ifindex);
+ if (mac->fwd_info.local.vid)
+ json_object_int_add(json_mac, "vlan",
+ mac->fwd_info.local.vid);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ json_object_string_add(json_mac, "type", "remote");
+ json_object_string_add(
+ json_mac, "remoteVtep",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
+ json_object_string_add(json_mac, "type", "auto");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
- vty_out(vty, " Default-gateway Mac ");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ json_object_boolean_true_add(json_mac, "stickyMac");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
- vty_out(vty, " Remote-gateway Mac ");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+ json_object_boolean_true_add(json_mac,
+ "defaultGateway");
- vty_out(vty, "\n");
- vty_out(vty, " Local Seq: %u Remote Seq: %u",
- mac->loc_seq, mac->rem_seq);
- vty_out(vty, "\n");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
+ json_object_boolean_true_add(json_mac,
+ "remoteGatewayMac");
- /* print all the associated neigh */
- vty_out(vty, " Neighbors:\n");
- if (!listcount(mac->neigh_list))
- vty_out(vty, " No Neighbors\n");
- else {
- for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
- vty_out(vty, " %s %s\n",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- (IS_ZEBRA_NEIGH_ACTIVE(n)
- ? "Active" : "Inactive"));
+ json_object_int_add(json_mac, "localSequence", mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
+
+ /* print all the associated neigh */
+ if (!listcount(mac->neigh_list))
+ json_object_string_add(json_mac, "neighbors", "none");
+ else {
+ json_object *json_active_nbrs = json_object_new_array();
+ json_object *json_inactive_nbrs =
+ json_object_new_array();
+ json_object *json_nbrs = json_object_new_object();
+
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ json_object_array_add(
+ json_active_nbrs,
+ json_object_new_string(
+ ipaddr2str(
+ &n->ip, buf2,
+ sizeof(buf2))));
+ else
+ json_object_array_add(
+ json_inactive_nbrs,
+ json_object_new_string(
+ ipaddr2str(
+ &n->ip, buf2,
+ sizeof(buf2))));
+ }
+
+ json_object_object_add(json_nbrs, "active",
+ json_active_nbrs);
+ json_object_object_add(json_nbrs, "inactive",
+ json_inactive_nbrs);
+ json_object_object_add(json_mac, "neighbors",
+ json_nbrs);
}
- }
- vty_out(vty, "\n");
+ json_object_object_add(json, buf1, json_mac);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else {
+ vty_out(vty, "MAC: %s\n", buf1);
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ ifindex_t ifindex;
+
+ ifindex = mac->fwd_info.local.ifindex;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ if (!ifp)
+ return;
+ vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex);
+ if (mac->fwd_info.local.vid)
+ vty_out(vty, " VLAN: %u",
+ mac->fwd_info.local.vid);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ vty_out(vty, " Remote VTEP: %s",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+ vty_out(vty, " Auto Mac ");
+ }
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ vty_out(vty, " Sticky Mac ");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+ vty_out(vty, " Default-gateway Mac ");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
+ 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))
+ vty_out(vty, " No Neighbors\n");
+ else {
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+ vty_out(vty, " %s %s\n",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ (IS_ZEBRA_NEIGH_ACTIVE(n)
+ ? "Active"
+ : "Inactive"));
+ }
+ }
+
+ vty_out(vty, "\n");
+ }
}
/*
/*
* Compare two neighbor hash structures.
*/
-static int neigh_cmp(const void *p1, const void *p2)
+static bool neigh_cmp(const void *p1, const void *p2)
{
const zebra_neigh_t *n1 = p1;
const zebra_neigh_t *n2 = p2;
if (n1 == NULL && n2 == NULL)
- return 1;
+ return true;
if (n1 == NULL || n2 == NULL)
- return 0;
+ return false;
return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0);
}
+static int neigh_list_cmp(void *p1, void *p2)
+{
+ const zebra_neigh_t *n1 = p1;
+ const zebra_neigh_t *n2 = p2;
+
+ return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr));
+}
+
/*
* Callback to allocate neighbor hash entry.
*/
/* mac entry should be present */
mac = zvni_mac_lookup(zvni, &n->emac);
if (!mac) {
- zlog_debug("MAC %s doesnt exists for neigh %s on VNI %u",
+ zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
return -1;
/* see if the mac needs to be deleted as well*/
if (mac)
- zvni_deref_ip2mac(zvni, mac, 0);
+ zvni_deref_ip2mac(zvni, mac);
return 0;
}
struct interface *ifp,
struct ipaddr *ip,
struct ethaddr *macaddr,
- uint8_t router_flag)
+ bool is_router)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
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))
- check_rbit = true;
-
- if (memcmp(n->emac.octet, macaddr->octet,
- ETH_ALEN) == 0) {
- /* Update any params and return - client doesn't
- * care about a purely local change.
- */
+ bool mac_different;
+ bool cur_is_router;
+
+ /* Note any changes and see if of interest to BGP. */
+ mac_different = (memcmp(n->emac.octet,
+ macaddr->octet, ETH_ALEN) != 0) ? 1 : 0;
+ cur_is_router = !!CHECK_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
+ if (!mac_different && is_router == cur_is_router) {
n->ifindex = ifp->ifindex;
- } else {
+ return 0;
+ }
- /* 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.
- */
- 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) {
- 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);
- }
+ if (!mac_different) {
+ /* Only the router flag has changed. */
+ if (is_router)
+ SET_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
- /* Update the forwarding info. */
- n->ifindex = ifp->ifindex;
- memcpy(&n->emac, macaddr, ETH_ALEN);
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ return zvni_neigh_send_add_to_client(
+ zvni->vni, ip, macaddr,
+ n->flags, n->loc_seq);
+ return 0;
+ }
- /* Link to new MAC */
- listnode_add_sort(zmac->neigh_list, n);
+ /* 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.
+ */
+ 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) {
+ 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);
}
+ /* Update the forwarding info. */
+ n->ifindex = ifp->ifindex;
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+
+ /* Link to new MAC */
+ listnode_add_sort(zmac->neigh_list, n);
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
/*
* Neighbor has moved from remote to local. Its
neigh_mac_change = upd_mac_seq = true;
listnode_delete(old_zmac->neigh_list,
n);
- zvni_deref_ip2mac(zvni, old_zmac, 0);
+ zvni_deref_ip2mac(zvni, old_zmac);
}
/* Link to new MAC */
}
/*Mark Router flag (R-bit) */
- if (router_flag)
+ if (is_router)
SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
else
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+ ZEBRA_NEIGH_SET_ACTIVE(n);
n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
}
/*
* Compare two MAC addresses.
*/
-static int mac_cmp(const void *p1, const void *p2)
+static bool mac_cmp(const void *p1, const void *p2)
{
const zebra_mac_t *pmac1 = p1;
const zebra_mac_t *pmac2 = p2;
if (pmac1 == NULL && pmac2 == NULL)
- return 1;
+ return true;
if (pmac1 == NULL || pmac2 == NULL)
- return 0;
+ return false;
return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
== 0);
assert(mac);
mac->neigh_list = list_new();
- mac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp;
+ mac->neigh_list->cmp = neigh_list_cmp;
return mac;
}
{
zebra_mac_t *tmp_mac;
- list_delete_and_null(&mac->neigh_list);
+ list_delete(&mac->neigh_list);
/* Free the VNI hash entry and allocated memory. */
tmp_mac = hash_release(zvni->mac_table, mac);
&wctx->r_vtep_ip))) {
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
zvni_mac_send_del_to_client(wctx->zvni->vni,
- &mac->macaddr, mac->flags);
+ &mac->macaddr);
}
if (wctx->uninstall)
/*
* Inform BGP about local MAC deletion.
*/
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
- uint8_t mac_flags)
+static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
{
- uint8_t flags = 0;
-
- if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
-
- return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- 0, ZEBRA_MACIP_DEL);
+ return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
+ 0 /* seq */, ZEBRA_MACIP_DEL);
}
/*
{
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
- uint8_t sticky;
+ bool sticky;
if (!(mac->flags & ZEBRA_MAC_REMOTE))
return 0;
return -1;
vxl = &zif->l2info.vxl;
- sticky = CHECK_FLAG(mac->flags,
- (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)) ? 1 : 0;
+ sticky = !!CHECK_FLAG(mac->flags,
+ (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr,
mac->fwd_info.r_vtep_ip, sticky);
{
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
- struct in_addr vtep_ip = {.s_addr = 0};
+ struct in_addr vtep_ip;
struct interface *ifp;
if (!(mac->flags & ZEBRA_MAC_REMOTE))
zvni_mac_install(wctx->zvni, mac);
}
+/*
+ * Count of remote neighbors referencing this MAC.
+ */
+static int remote_neigh_count(zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ int count = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
+ count++;
+ }
+
+ return count;
+}
+
/*
* Decrement neighbor refcount of MAC; uninstall and free it if
* appropriate.
*/
-static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
- int uninstall)
+static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
{
- if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)
- || !list_isempty(mac->neigh_list))
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
return;
- if (uninstall)
+ /* If all remote neighbors referencing a remote MAC go away,
+ * we need to uninstall the MAC.
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
+ remote_neigh_count(mac) == 0) {
zvni_mac_uninstall(zvni, mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ }
- zvni_mac_del(zvni, mac);
+ /* If no neighbors, delete the MAC. */
+ if (list_isempty(mac->neigh_list))
+ zvni_mac_del(zvni, mac);
}
/*
/*
* Compare 2 VNI hash entries.
*/
-static int vni_hash_cmp(const void *p1, const void *p2)
+static bool vni_hash_cmp(const void *p1, const void *p2)
{
const zebra_vni_t *zvni1 = p1;
const zebra_vni_t *zvni2 = p2;
return (zvni1->vni == zvni2->vni);
}
+static int vni_list_cmp(void *p1, void *p2)
+{
+ const zebra_vni_t *zvni1 = p1;
+ const zebra_vni_t *zvni2 = p2;
+
+ if (zvni1->vni == zvni2->vni)
+ return 0;
+ return (zvni1->vni < zvni2->vni) ? -1 : 1;
+}
+
/*
* Callback to allocate VNI hash entry.
*/
*/
static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip)
{
- return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
+ if (is_vxlan_flooding_head_end())
+ return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
+ return 0;
}
/*
return kernel_del_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
}
+/*
+ * Install or uninstall flood entries in the kernel corresponding to
+ * remote VTEPs. This is invoked upon change to BUM handling.
+ */
+static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet,
+ void *zvrf)
+{
+ zebra_vni_t *zvni;
+ zebra_vtep_t *zvtep;
+
+ zvni = (zebra_vni_t *)backet->data;
+ if (!zvni)
+ return;
+
+ for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
+ if (is_vxlan_flooding_head_end())
+ zvni_vtep_install(zvni, &zvtep->vtep_ip);
+ else
+ zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
+ }
+}
+
/*
* Cleanup VNI/VTEP and update kernel
*/
/*
* Compare 2 L3 VNI hash entries.
*/
-static int l3vni_hash_cmp(const void *p1, const void *p2)
+static bool l3vni_hash_cmp(const void *p1, const void *p2)
{
const zebra_l3vni_t *zl3vni1 = p1;
const zebra_l3vni_t *zl3vni2 = p2;
*/
static zebra_l3vni_t *zl3vni_lookup(vni_t vni)
{
- struct zebra_ns *zns;
zebra_l3vni_t tmp_l3vni;
zebra_l3vni_t *zl3vni = NULL;
- zns = zebra_ns_lookup(NS_DEFAULT);
- assert(zns);
memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t));
tmp_l3vni.vni = vni;
- zl3vni = hash_lookup(zns->l3vni_table, &tmp_l3vni);
+ zl3vni = hash_lookup(zrouter.l3vni_table, &tmp_l3vni);
return zl3vni;
}
static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id)
{
zebra_l3vni_t tmp_zl3vni;
- struct zebra_ns *zns = NULL;
zebra_l3vni_t *zl3vni = NULL;
- zns = zebra_ns_lookup(NS_DEFAULT);
- assert(zns);
-
memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t));
tmp_zl3vni.vni = vni;
- zl3vni = hash_get(zns->l3vni_table, &tmp_zl3vni, zl3vni_alloc);
+ zl3vni = hash_get(zrouter.l3vni_table, &tmp_zl3vni, zl3vni_alloc);
assert(zl3vni);
zl3vni->vrf_id = vrf_id;
zl3vni->svi_if = NULL;
zl3vni->vxlan_if = NULL;
zl3vni->l2vnis = list_new();
- zl3vni->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp;
+ zl3vni->l2vnis->cmp = vni_list_cmp;
/* Create hash table for remote RMAC */
zl3vni->rmac_table = hash_create(mac_hash_keymake, mac_cmp,
*/
static int zl3vni_del(zebra_l3vni_t *zl3vni)
{
- struct zebra_ns *zns;
zebra_l3vni_t *tmp_zl3vni;
- zns = zebra_ns_lookup(NS_DEFAULT);
- assert(zns);
-
/* free the list of l2vnis */
- list_delete_and_null(&zl3vni->l2vnis);
+ list_delete(&zl3vni->l2vnis);
zl3vni->l2vnis = NULL;
/* Free the rmac table */
zl3vni->nh_table = NULL;
/* Free the VNI hash entry and allocated memory. */
- tmp_zl3vni = hash_release(zns->l3vni_table, zl3vni);
+ tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni);
if (tmp_zl3vni)
XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
uint32_t tmp_seq;
- uint8_t sticky = 0;
- uint8_t remote_gw = 0;
- uint8_t router_flag = 0;
+ bool sticky;
+ bool remote_gw;
+ bool is_router;
/* Locate VNI hash entry - expected to exist. */
zvni = zvni_lookup(vni);
zvni_vtep_install(zvni, &vtep_ip);
}
- 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);
+ sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
mac = zvni_mac_lookup(zvni, macaddr);
*/
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
+ || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
+ || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
|| !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
|| seq != mac->rem_seq)
update_mac = 1;
}
}
+ /* Remove local MAC from BGP. */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+ zvni_mac_send_del_to_client(zvni->vni, macaddr);
+
/* Set "auto" and "remote" forwarding info. */
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
/* Install the entry. */
zvni_mac_install(zvni, mac);
+
}
/* Update seq number. */
n = zvni_neigh_lookup(zvni, ipaddr);
if (!n
|| !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
|| (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;
vni,
prefix_mac2str(macaddr,
buf, sizeof(buf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr,
- buf1, sizeof(buf1)) : "",
+ " IP ",
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
n_type,
tmp_seq);
return;
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);
+ zvni_deref_ip2mac(zvni, old_mac);
}
listnode_add_sort(mac->neigh_list, n);
memcpy(&n->emac, macaddr, ETH_ALEN);
&& (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);
+ zvni_deref_ip2mac(zvni, mac);
}
} else {
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
zvni_process_neigh_on_remote_mac_del(zvni, mac);
+ /*
+ * the remote sequence number in the auto mac entry
+ * needs to be reset to 0 as the mac entry may have
+ * been removed on all VTEPs (including
+ * the originating one)
+ */
+ mac->rem_seq = 0;
- if (list_isempty(mac->neigh_list)) {
+ /* If all remote neighbors referencing a remote MAC
+ * go away, we need to uninstall the MAC.
+ */
+ if (remote_neigh_count(mac) == 0) {
zvni_mac_uninstall(zvni, mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ }
+ if (list_isempty(mac->neigh_list))
zvni_mac_del(zvni, mac);
- } else
+ else
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
}
}
if (use_json)
vty_out(vty, "{}\n");
else
- vty_out(vty, "%% L3-VNI %u doesnt exist\n", l3vni);
+ vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni);
return;
}
vty_out(vty, "{}\n");
else
vty_out(vty,
- "%% Requested RMAC doesnt exist in L3-VNI %u",
+ "%% Requested RMAC doesn't exist in L3-VNI %u",
l3vni);
return;
}
void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json)
{
- struct zebra_ns *zns = NULL;
json_object *json = NULL;
void *args[2];
return;
}
- zns = zebra_ns_lookup(NS_DEFAULT);
- if (!zns) {
- if (use_json)
- vty_out(vty, "{}\n");
- return;
- }
-
if (use_json)
json = json_object_new_object();
args[0] = vty;
args[1] = json;
- hash_iterate(zns->l3vni_table,
+ hash_iterate(zrouter.l3vni_table,
(void (*)(struct hash_backet *,
void *))zl3vni_print_rmac_hash_all_vni,
args);
void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json)
{
- struct zebra_ns *zns = NULL;
json_object *json = NULL;
void *args[2];
return;
}
- zns = zebra_ns_lookup(NS_DEFAULT);
- if (!zns)
- return;
-
if (use_json)
json = json_object_new_object();
args[0] = vty;
args[1] = json;
- hash_iterate(zns->l3vni_table,
+ hash_iterate(zrouter.l3vni_table,
(void (*)(struct hash_backet *,
void *))zl3vni_print_nh_hash_all_vni,
args);
* Display specific MAC for a VNI, if present (VTY command handler).
*/
void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni, struct ethaddr *macaddr)
+ vni_t vni, struct ethaddr *macaddr,
+ bool use_json)
{
zebra_vni_t *zvni;
zebra_mac_t *mac;
+ json_object *json = NULL;
if (!is_evpn_enabled())
return;
+
zvni = zvni_lookup(vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac) {
- vty_out(vty, "%% Requested MAC does not exist in VNI %u\n",
- vni);
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty,
+ "%% Requested MAC does not exist in VNI %u\n",
+ vni);
return;
}
- zvni_print_mac(mac, vty);
+ if (use_json)
+ json = json_object_new_object();
+
+ zvni_print_mac(mac, vty, json);
}
/*
int num_l3vnis = 0;
int num_vnis = 0;
json_object *json = NULL;
- struct zebra_ns *zns = NULL;
struct zebra_vrf *zvrf = NULL;
if (!is_evpn_enabled())
return;
- zns = zebra_ns_lookup(NS_DEFAULT);
- if (!zns)
- return;
-
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
return;
- num_l3vnis = hashcount(zns->l3vni_table);
+ num_l3vnis = hashcount(zrouter.l3vni_table);
num_l2vnis = hashcount(zvrf->vni_table);
num_vnis = num_l2vnis + num_l3vnis;
bool use_json)
{
json_object *json = NULL;
- struct zebra_ns *zns = NULL;
void *args[2];
if (!is_evpn_enabled())
return;
- zns = zebra_ns_lookup(NS_DEFAULT);
- if (!zns)
- return;
-
-
if (use_json)
json = json_object_new_object();
else
args);
/* Display all L3-VNIs */
- hash_iterate(zns->l3vni_table,
+ hash_iterate(zrouter.l3vni_table,
(void (*)(struct hash_backet *, void *))zl3vni_print_hash,
args);
struct ipaddr *ip,
struct ethaddr *macaddr,
uint16_t state,
- uint8_t ext_learned,
- uint8_t router_flag)
+ bool is_ext,
+ bool is_router)
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
"Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, state, ext_learned ? "ext-learned " : "",
- router_flag ? "router " : "",
+ ifp->ifindex, state, is_ext ? "ext-learned " : "",
+ is_router ? "router " : "",
zvni->vni);
/* Is this about a local neighbor or a remote one? */
- if (!ext_learned)
+ if (!is_ext)
return zvni_local_neigh_update(zvni, ifp, ip, macaddr,
- router_flag);
+ is_router);
return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
}
ifp->ifindex, vni);
/* Remove MAC from BGP. */
- zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
+ zvni_mac_send_del_to_client(zvni->vni, macaddr);
/*
* If there are no neigh associated with the mac delete the 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);
+ zvni_mac_send_del_to_client(zvni->vni, macaddr);
/*
* If there are no neigh associated with the mac delete the mac
int zebra_vxlan_local_mac_add_update(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
- uint8_t sticky)
+ bool sticky)
{
zebra_vni_t *zvni;
zebra_mac_t *mac;
return 0;
}
+/*
+ * Handle message from client to specify the flooding mechanism for
+ * BUM packets. The default is to do head-end (ingress) replication
+ * and the other supported option is to disable it. This applies to
+ * all BUM traffic and disabling it applies to both the transmit and
+ * receive direction.
+ */
+void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ enum vxlan_flood_control flood_ctrl;
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT) {
+ zlog_err("EVPN flood control for non-default VRF %u",
+ zvrf_id(zvrf));
+ return;
+ }
+
+ s = msg;
+ STREAM_GETC(s, flood_ctrl);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("EVPN flood control %u, currently %u",
+ flood_ctrl, zvrf->vxlan_flood_ctrl);
+
+ if (zvrf->vxlan_flood_ctrl == flood_ctrl)
+ return;
+
+ zvrf->vxlan_flood_ctrl = flood_ctrl;
+
+ /* Install or uninstall flood entries corresponding to
+ * remote VTEPs.
+ */
+ hash_iterate(zvrf->vni_table, zvni_handle_flooding_remote_vteps,
+ zvrf);
+
+stream_failure:
+ return;
+}
+
/*
* Handle message from client to enable/disable advertisement of g/w macip
* routes
* When enabled, the VNI hash table will be built and MAC FDB table read;
* when disabled, the entries should be deleted and remote VTEPs and MACs
* uninstalled from the kernel.
+ * This also informs the setting for BUM handling at the time this change
+ * occurs; it is relevant only when specifying "learn".
*/
void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
{
struct stream *s = NULL;
int advertise = 0;
- struct zebra_ns *zns = NULL;
+ enum vxlan_flood_control flood_ctrl;
if (zvrf_id(zvrf) != VRF_DEFAULT) {
zlog_debug("EVPN VNI Adv for non-default VRF %u",
s = msg;
STREAM_GETC(s, advertise);
+ STREAM_GETC(s, flood_ctrl);
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("EVPN VNI Adv %s, currently %s",
+ zlog_debug("EVPN VNI Adv %s, currently %s, flood control %u",
advertise ? "enabled" : "disabled",
- is_evpn_enabled() ? "enabled" : "disabled");
+ is_evpn_enabled() ? "enabled" : "disabled",
+ flood_ctrl);
if (zvrf->advertise_all_vni == advertise)
return;
zvrf->advertise_all_vni = advertise;
if (is_evpn_enabled()) {
+ /* Note BUM handling */
+ zvrf->vxlan_flood_ctrl = flood_ctrl;
+
/* Build VNI hash table and inform BGP. */
zvni_build_hash_table();
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
/* cleanup all l3vnis */
- zns = zebra_ns_lookup(NS_DEFAULT);
- if (!zns)
- return;
-
- hash_iterate(zns->l3vni_table, zl3vni_cleanup_all, NULL);
+ hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);
}
stream_failure:
/* init the l3vni table */
void zebra_vxlan_ns_init(struct zebra_ns *zns)
{
- zns->l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
- "Zebra VRF L3 VNI table");
+ zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
+ "Zebra VRF L3 VNI table");
}
/* free l3vni table */
void zebra_vxlan_ns_disable(struct zebra_ns *zns)
{
- hash_free(zns->l3vni_table);
+ hash_free(zrouter.l3vni_table);
}
/* get the l3vni svi ifindex */