static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
static int zl3vni_del(zebra_l3vni_t *zl3vni);
static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t);
-static vni_t zvni_get_l3vni(zebra_vni_t *zvni);
static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
-static void zvni_get_rmac(zebra_vni_t *zvni, struct ethaddr *rmac);
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
if (!json) {
vty_out(vty, "VNI: %u\n", zl3vni->vni);
+ vty_out(vty, " Local Vtep Ip: %s",
+ inet_ntoa(zl3vni->local_vtep_ip));
vty_out(vty, " Vxlan-Intf: %s\n",
zl3vni_vxlan_if_name(zl3vni));
vty_out(vty, " SVI-If: %s\n",
} else {
json_vni_list = json_object_new_array();
json_object_int_add(json, "vni", zl3vni->vni);
+ json_object_string_add(json, "local-vtep-ip",
+ inet_ntoa(zl3vni->local_vtep_ip));
json_object_string_add(json, "vxlan-intf",
zl3vni_vxlan_if_name(zl3vni));
json_object_string_add(json, "svi-if",
return;
if (!json) {
- vty_out(vty, "%-10u %-20s %-20s %-5s %-37s %-18s\n",
+ vty_out(vty, "%-10u %-15s %-20s %-20s %-5s %-37s %-18s\n",
zl3vni->vni,
+ inet_ntoa(zl3vni->local_vtep_ip),
zl3vni_vxlan_if_name(zl3vni),
zl3vni_svi_if_name(zl3vni),
zl3vni_state2str(zl3vni),
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
json_vni = json_object_new_object();
json_object_int_add(json_vni, "vni", zl3vni->vni);
+ json_object_string_add(json_vni, "local-ip",
+ inet_ntoa(zl3vni->local_vtep_ip));
json_object_string_add(json_vni, "vxlan-if",
zl3vni_vxlan_if_name(zl3vni));
json_object_string_add(json_vni, "svi-if",
s = client->obuf;
stream_reset(s);
- zserv_create_header(s, cmd, VRF_DEFAULT);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
stream_putl(s, vni);
stream_put(s, macaddr->octet, ETH_ALEN);
if (ip) {
static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
struct ethaddr *macaddr, struct ipaddr *ip)
{
- vni_t l3vni = 0;
- struct ethaddr rmac;
char buf[ETHER_ADDR_STRLEN];
- char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zebra_neigh_t *n = NULL;
zebra_mac_t *mac = NULL;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- memset(&rmac, 0, sizeof(struct ethaddr));
-
zif = zvni->vxlan_if->info;
if (!zif)
return -1;
vxl = &zif->l2info.vxl;
- /* get the l3-vni */
- l3vni = zvni_get_l3vni(zvni);
-
- /* get the rmac */
- zvni_get_rmac(zvni, &rmac);
-
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac) {
mac = zvni_mac_add(zvni, macaddr);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "SVI %s(%u) L2-VNI %u L3-VNI %u RMAC %s , sending GW MAC %s IP %s add to BGP",
+ "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP",
ifp->name, ifp->ifindex, zvni->vni,
- l3vni,
- prefix_mac2str(&rmac, buf1, sizeof(buf1)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)));
static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
struct ipaddr *ip)
{
- vni_t l3vni = 0;
- struct ethaddr rmac;
- char buf[ETHER_ADDR_STRLEN];
char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zebra_neigh_t *n = NULL;
zebra_mac_t *mac = NULL;
- memset(&rmac, 0, sizeof(struct ethaddr));
-
- /* get the l30vni */
- l3vni = zvni_get_l3vni(zvni);
-
- /* get the rmac */
- zvni_get_rmac(zvni, &rmac);
-
/* If the neigh entry is not present nothing to do*/
n = zvni_neigh_lookup(zvni, ip);
if (!n)
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "SVI %s(%u) L2-VNI %u, L3-VNI %u RMAC %s sending GW MAC %s IP %s del to BGP",
- ifp->name, ifp->ifindex, zvni->vni, l3vni,
- prefix_mac2str(&rmac, buf, sizeof(buf)),
+ "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP",
+ ifp->name, ifp->ifindex, zvni->vni,
prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)));
s = client->obuf;
stream_reset(s);
- zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
+ zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
stream_putl(s, zvni->vni);
stream_put_in_addr(s, &zvni->local_vtep_ip);
stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
s = client->obuf;
stream_reset(s);
- zserv_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
+ zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
stream_putl(s, vni);
/* Write packet size. */
}
/* associate with vxlan_if */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
zl3vni->vxlan_if = ifp;
- /* we need to associate with SVI.
+ /*
+ * we need to associate with SVI.
* we can associate with svi-if only after association
- * with vxlan-intf is complete */
+ * with vxlan-intf is complete
+ */
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
if (is_l3vni_oper_up(zl3vni))
zvni_del(zvni);
}
+/* cleanup L3VNI */
+static void zl3vni_cleanup_all(struct hash_backet *backet,
+ void *args)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = (zebra_l3vni_t *)backet->data;
+ if (!zl3vni)
+ return;
+
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+}
+
static int is_host_present_in_host_list(struct list *list,
struct prefix *host)
{
zebra_mac_t *tmp_rmac;
if (zrmac->host_list)
- list_delete(zrmac->host_list);
+ list_delete_and_null(&zrmac->host_list);
zrmac->host_list = NULL;
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
return 0;
if (!zl3vni->vxlan_if) {
- zlog_err("RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
+ zlog_err(
+ "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
zl3vni->vni, zl3vni);
return -1;
zebra_neigh_t *tmp_n;
if (n->host_list)
- list_delete(n->host_list);
+ list_delete_and_null(&n->host_list);
n->host_list = NULL;
tmp_n = hash_release(zl3vni->nh_table, n);
return 0;
}
+/* handle neigh update from kernel - the only thing of interest is to
+ * readd stale entries.
+ */
+static int zl3vni_local_nh_add_update(zebra_l3vni_t *zl3vni,
+ struct ipaddr *ip, u_int16_t state)
+{
+#ifdef GNU_LINUX
+ zebra_neigh_t *n = NULL;
+
+ n = zl3vni_nh_lookup(zl3vni, ip);
+ if (!n)
+ return 0;
+
+ /* all next hop neigh are remote and installed by frr.
+ * If the kernel has aged this entry, re-install.
+ */
+ if (state & NUD_STALE)
+ zl3vni_nh_install(zl3vni, n);
+#endif
+ return 0;
+}
+
+/* handle neigh delete from kernel */
+static int zl3vni_local_nh_del(zebra_l3vni_t *zl3vni,
+ struct ipaddr *ip)
+{
+ zebra_neigh_t *n = NULL;
+
+ n = zl3vni_nh_lookup(zl3vni, ip);
+ if (!n)
+ return 0;
+
+ /* all next hop neigh are remote and installed by frr.
+ * If we get an age out notification for these neigh entries, we have to
+ * install it back
+ */
+ zl3vni_nh_install(zl3vni, n);
+
+ return 0;
+}
+
/*
* Hash function for L3 VNI.
*/
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == zl3vni->vni)
+ if (vxl->vni == zl3vni->vni) {
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
return ifp;
+ }
}
return NULL;
struct ethaddr rmac;
char buf[ETHER_ADDR_STRLEN];
- client = zebra_find_client(ZEBRA_ROUTE_BGP);
+ client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
if (!client)
return 0;
s = client->obuf;
stream_reset(s);
- zserv_create_header(s, ZEBRA_L3VNI_ADD,
+ zclient_create_header(s, ZEBRA_L3VNI_ADD,
zl3vni_vrf_id(zl3vni));
stream_putl(s, zl3vni->vni);
stream_put(s, &rmac, sizeof(struct ethaddr));
+ stream_put_in_addr(s, &zl3vni->local_vtep_ip);
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send L3_VNI_ADD %u VRF %s RMAC %s to %s",
+ zlog_debug("Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s to %s",
zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
prefix_mac2str(&rmac, buf, sizeof(buf)),
+ inet_ntoa(zl3vni->local_vtep_ip),
zebra_route_string(client->proto));
client->l3vniadd_cnt++;
struct stream *s = NULL;
struct zserv *client = NULL;
- client = zebra_find_client(ZEBRA_ROUTE_BGP);
+ client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
if (!client)
return 0;
s = client->obuf;
stream_reset(s);
- zserv_create_header(s, ZEBRA_L3VNI_DEL,
+ zclient_create_header(s, ZEBRA_L3VNI_DEL,
zl3vni_vrf_id(zl3vni));
stream_putl(s, zl3vni->vni);
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni)
{
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("L3-VNI %u is UP - send add to BGP and update all neigh enries",
+ zlog_debug("L3-VNI %u is UP - send add to BGP",
zl3vni->vni);
/* send l3vni add to BGP */
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni)
{
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("L3-VNI %u is Down - send del to BGP and update all neigh enries",
+ zlog_debug("L3-VNI %u is Down - Send del to BGP",
zl3vni->vni);
/* send l3-vni del to BGP*/
listnode_add_sort(zl3vni->l2vnis, zvni);
}
-/* l3vni from zvni */
-static vni_t zvni_get_l3vni(zebra_vni_t *zvni)
-{
- zebra_l3vni_t *zl3vni = NULL;
-
- zl3vni = zl3vni_from_vrf(zvni->vrf_id);
- if (!zl3vni || !is_l3vni_oper_up(zl3vni))
- return 0;
-
- return zl3vni->vni;
-}
-
-/* rmac from l3vni */
-static void zvni_get_rmac(zebra_vni_t *zvni,
- struct ethaddr *rmac)
-{
- zebra_l3vni_t *zl3vni = NULL;
-
- zl3vni = zl3vni_from_vrf(zvni->vrf_id);
- if (!zl3vni || !is_l3vni_oper_up(zl3vni))
- return;
-
- if (zl3vni->svi_if)
- memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN);
-}
-
/*
* handle transition of vni from l2 to l3 and vice versa
*/
* that it can be reprogrammed as L3-VNI in the system. It is also
* possible that the vrf-vni mapping is removed from FRR while the vxlan
* interface is still present in kernel. In this case to keep it
- * symmetric, we will delete the l3-vni and reprogram it as l2-vni */
+ * symmetric, we will delete the l3-vni and reprogram it as l2-vni
+ */
if (add) {
/* Locate hash entry */
zvni = zvni_lookup(vni);
/* TODO_MITESH: This needs to be thought through. We don't have
* enough information at this point to reprogram the vni as
* l2-vni. One way is to store the required info in l3-vni and
- * used it solely for this purpose */
+ * used it solely for this purpose
+ */
}
return 0;
json_object_int_add(json, "numVnis", num_vnis);
} else {
vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis);
- vty_out(vty, "%-10s %-20s %-20s %-5s %-37s %-18s\n", "VNI",
- "Vx-intf", "L3-SVI", "State", "VRF", "Rmac");
+ vty_out(vty, "%-10s %-15s %-20s %-20s %-5s %-37s %-18s\n",
+ "VNI", "Local-ip", "Vx-intf", "L3-SVI", "State",
+ "VRF", "Rmac");
}
args[0] = vty;
int zebra_vxlan_local_neigh_del(struct interface *ifp,
struct interface *link_if, struct ipaddr *ip)
{
- vni_t l3vni = 0;
- struct ethaddr rmac;
char buf[INET6_ADDRSTRLEN];
- char buf1[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
zebra_neigh_t *n = NULL;
zebra_vni_t *zvni = NULL;
zebra_mac_t *zmac = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
- memset(&rmac, 0, sizeof(struct ethaddr));
+ /* check if this is a remote neigh entry corresponding to remote
+ * next-hop
+ */
+ zl3vni = zl3vni_from_svi(ifp, link_if);
+ if (zl3vni)
+ return zl3vni_local_nh_del(zl3vni, ip);
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
zvni = zvni_from_svi(ifp, link_if);
if (!zvni)
return 0;
+
if (!zvni->vxlan_if) {
zlog_err(
"VNI %u hash %p doesn't have intf upon local neighbor DEL",
return -1;
}
- /* get the l3-vni */
- l3vni = zvni_get_l3vni(zvni);
-
- /* get the rmac */
- zvni_get_rmac(zvni, &rmac);
-
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u L3-VNI %u RMAC %s",
+ zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u",
ipaddr2str(ip, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni,
- l3vni, prefix_mac2str(&rmac, buf1, sizeof(buf1)));
+ ifp->name, ifp->ifindex, zvni->vni);
/* If entry doesn't exist, nothing to do. */
n = zvni_neigh_lookup(zvni, ip);
struct ethaddr *macaddr, u_int16_t state,
u_char ext_learned)
{
- vni_t l3vni = 0;
- struct ethaddr rmac;
char buf[ETHER_ADDR_STRLEN];
- char buf1[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
zebra_vni_t *zvni = NULL;
zebra_neigh_t *n = NULL;
zebra_mac_t *zmac = NULL, *old_zmac = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
- memset(&rmac, 0, sizeof(struct ethaddr));
+ /* check if this is a remote neigh entry corresponding to remote
+ * next-hop
+ */
+ zl3vni = zl3vni_from_svi(ifp, link_if);
+ if (zl3vni)
+ return zl3vni_local_nh_add_update(zl3vni, ip, state);
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
if (!zvni)
return 0;
- /* get the l3-vni */
- l3vni = zvni_get_l3vni(zvni);
-
- /* get the rmac */
- zvni_get_rmac(zvni, &rmac);
-
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u L3-VNI %u RMAC %s",
+ "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
- zvni->vni, l3vni,
- prefix_mac2str(&rmac, buf1, sizeof(buf1)));
+ zvni->vni);
/* create a dummy MAC if the MAC is not already present */
zmac = zvni_mac_lookup(zvni, macaddr);
/* Inform BGP. */
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u L3-VNI %u with RMAC %s",
+ zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni,
- l3vni,
- prefix_mac2str(&rmac, buf1, sizeof(buf1)));
-
+ zvni->vni);
ZEBRA_NEIGH_SET_ACTIVE(n);
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
}
/* we need to associate with SVI, if any, we can associate with
- * svi-if only after association with vxlan-intf is complete */
+ * svi-if only after association with vxlan-intf is complete
+ */
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
if (is_l3vni_oper_up(zl3vni))
zebra_vxlan_process_l3vni_oper_down(zl3vni);
/* remove the association with vxlan_if */
+ memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
zl3vni->vxlan_if = NULL;
} else {
}
/* access-vlan change - process oper down, associate with new
- * svi_if and then process oper up again */
+ * svi_if and then process oper up again
+ */
if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
if (if_is_operative(ifp)) {
zebra_vxlan_process_l3vni_oper_down(zl3vni);
}
/* associate with vxlan_if */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
zl3vni->vxlan_if = ifp;
/* Associate with SVI, if any. We can associate with svi-if only
}
int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
- vni_t vni, char *err,
+ vni_t vni,
+ char *err, int err_str_sz,
int add)
{
zebra_l3vni_t *zl3vni = NULL;
/* check if the vni is already present under zvrf */
if (zvrf->l3vni) {
- snprintf(err, ERR_STR_SZ,
+ snprintf(err, err_str_sz,
"VNI is already configured under the vrf");
return -1;
}
/* check if this VNI is already present in the system */
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
- snprintf(err, ERR_STR_SZ,
+ snprintf(err, err_str_sz,
"VNI is already configured as L3-VNI");
return -1;
}
/* add the L3-VNI to the global table */
zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
if (!zl3vni) {
- snprintf(err, ERR_STR_SZ,
+ snprintf(err, err_str_sz,
"Could not add L3-VNI");
return -1;
}
zvrf->l3vni = vni;
/* associate with vxlan-intf;
- * we need to associate with the vxlan-intf first */
+ * we need to associate with the vxlan-intf first
+ */
zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
/* associate with corresponding SVI interface, we can associate
* with svi-if only after vxlan interface association is
- * complete */
+ * complete
+ */
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
/* formulate l2vni list */
} else {
zl3vni = zl3vni_lookup(vni);
if (!zl3vni) {
- snprintf(err, ERR_STR_SZ, "VNI doesn't exist");
+ snprintf(err, err_str_sz, "VNI doesn't exist");
return -1;
}
int zebra_vxlan_advertise_all_vni(struct zserv *client,
u_short length, struct zebra_vrf *zvrf)
{
- struct stream *s;
- int advertise;
+ struct stream *s = NULL;
+ int advertise = 0;
+ struct zebra_ns *zns = NULL;
if (zvrf_id(zvrf) != VRF_DEFAULT) {
zlog_err("EVPN VNI Adv for non-default VRF %u",
* kernel and free entries.
*/
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+
+ /* cleanup all l3vnis */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ if (!zns)
+ return -1;
+
+ hash_iterate(zns->l3vni_table, zl3vni_cleanup_all, NULL);
}
stream_failure: