#include "lib/json.h"
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
+DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
struct ethaddr *macaddr, u_char flags);
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
-static zebra_vni_t *zvni_map_svi(struct interface *ifp,
+static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if);
static struct interface *zvni_map_to_svi(vlanid_t vid,
struct interface *br_if);
+/* l3-vni next-hop neigh related APIs */
+/*static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+ struct ipaddr *ip);
+static void *zl3vni_nh_alloc(void *p);
+static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+ struct ipaddr *vtep_ip,
+ struct ethaddr *rmac);
+static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
+static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
+static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);*/
+
+/* l3-vni rmac related APIs */
+static void zl3vni_print_rmac_hash(struct hash_backet *, void *);
+static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *, void *);
+/*static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac);
+static void *zl3vni_rmac_alloc(void *p);
+static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac);
+static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
+static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
+static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni,
+ zebra_mac_t *zrmac);*/
+
+/* l3-vni related APIs*/
+static int is_vni_l3(vni_t);
+static zebra_l3vni_t *zl3vni_lookup(vni_t vni);
+static void *zl3vni_alloc(void *p);
+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);
+
static unsigned int mac_hash_keymake(void *p);
static int mac_cmp(const void *p1, const void *p2);
static void *zvni_mac_alloc(void *p);
}
}
+static void zl3vni_print_nh_hash(struct hash_backet *backet,
+ void *ctx)
+{
+ struct nh_walk_ctx *wctx = NULL;
+ struct vty *vty = NULL;
+ struct json_object *json = NULL;
+ struct json_object *json_nh = NULL;
+ zebra_neigh_t *n = NULL;
+ char buf1[ETHER_ADDR_STRLEN];
+
+ wctx = (struct nh_walk_ctx *)ctx;
+ vty = wctx->vty;
+ json = wctx->json;
+ if (json)
+ json_nh = json_object_new_object();
+ n = (zebra_neigh_t *)backet->data;
+ if (!n)
+ return;
+
+ if (!json) {
+ vty_out(vty, "%15s %-17s %6d\n",
+ inet_ntoa(n->r_vtep_ip),
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
+ n->nh_refcnt);
+ } else {
+ json_object_string_add(json_nh, "vtep-ip",
+ inet_ntoa(n->r_vtep_ip));
+ json_object_string_add(json_nh, "rmac",
+ prefix_mac2str(&n->emac, buf1,
+ sizeof(buf1)));
+ json_object_int_add(json_nh, "refCnt", n->nh_refcnt);
+ }
+}
+
+static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet,
+ void *ctx)
+{
+ struct vty *vty = NULL;
+ json_object *json = NULL;
+ json_object *json_vni = NULL;
+ json_object *json_mac = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+ u_int32_t num_rmacs;
+ struct rmac_walk_ctx *wctx = NULL;
+ char vni_str[VNI_STR_LEN];
+
+ wctx = (struct rmac_walk_ctx *)ctx;
+ vty = (struct vty *)wctx->vty;
+ json = (struct json_object *)wctx->json;
+
+ zl3vni = (zebra_l3vni_t *)backet->data;
+ if (!zl3vni) {
+ if (json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ num_rmacs = hashcount(zl3vni->rmac_table);
+ if (!num_rmacs)
+ return;
+
+ if (json) {
+ json_vni = json_object_new_object();
+ json_mac = json_object_new_array();
+ snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+ }
+
+ if (json == NULL) {
+ vty_out(vty, "\nVNI %u #MACs %u\n\n",
+ zl3vni->vni, num_rmacs);
+ vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
+ "Remote VTEP", "Refcnt");
+ } else
+ json_object_int_add(json_vni, "numRmacs", num_rmacs);
+
+ /* assign per-vni to wctx->json object to fill macs
+ * under the vni. Re-assign primary json object to fill
+ * next vni information.
+ */
+ wctx->json = json_mac;
+ hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, wctx);
+ wctx->json = json;
+ if (json) {
+ json_object_object_add(json_vni, "rmacs", json_mac);
+ json_object_object_add(json, vni_str, json_vni);
+ }
+}
+
+static void zl3vni_print_rmac_hash(struct hash_backet *backet,
+ void *ctx)
+{
+ zebra_mac_t *zrmac = NULL;
+ struct rmac_walk_ctx *wctx = NULL;
+ struct vty *vty = NULL;
+ struct json_object *json = NULL;
+ struct json_object *json_rmac = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+
+ wctx = (struct rmac_walk_ctx *)ctx;
+ vty = wctx->vty;
+ json = wctx->json;
+ if (json)
+ json_rmac = json_object_new_object();
+ zrmac = (zebra_mac_t *)backet->data;
+ if (!zrmac)
+ return;
+
+ if (!json) {
+ vty_out(vty, "%-17s %-21s %-6d\n",
+ prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
+ inet_ntoa(zrmac->fwd_info.r_vtep_ip),
+ zrmac->rmac_refcnt);
+ } else {
+ json_object_string_add(json_rmac, "rmac",
+ prefix_mac2str(&zrmac->macaddr, buf,
+ sizeof(buf)));
+ json_object_string_add(json_rmac, "vtep-ip",
+ inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+ json_object_int_add(json_rmac, "refcnt", zrmac->rmac_refcnt);
+ json_object_array_add(json, json_rmac);
+ }
+}
+
+/* print a specific L3 VNI entry */
+static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ struct vty *vty = NULL;
+ json_object *json = NULL;
+ zebra_vni_t *zvni = NULL;
+ json_object *json_vni_list = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ vty = ctx[0];
+ json = ctx[1];
+
+ if (!json) {
+ vty_out(vty, "VNI: %u\n", zl3vni->vni);
+ vty_out(vty, " Vxlan-Intf: %s\n",
+ zl3vni_vxlan_if_name(zl3vni));
+ vty_out(vty, " SVI-If: %s\n",
+ zl3vni_svi_if_name(zl3vni));
+ vty_out(vty, " State: %s\n",
+ zl3vni_state2str(zl3vni));
+ vty_out(vty, " Vrf: %s\n",
+ zl3vni_vrf_name(zl3vni));
+ vty_out(vty, " Rmac: %s\n",
+ zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+ vty_out(vty, " L2-VNIs: ");
+ for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
+ vty_out(vty, "%u ", zvni->vni);
+ vty_out(vty, "\n");
+ } else {
+ json_vni_list = json_object_new_array();
+ json_object_int_add(json, "vni", zl3vni->vni);
+ json_object_string_add(json, "vxlan-intf",
+ zl3vni_vxlan_if_name(zl3vni));
+ json_object_string_add(json, "svi-if",
+ zl3vni_svi_if_name(zl3vni));
+ json_object_string_add(json, "state",
+ zl3vni_state2str(zl3vni));
+ json_object_string_add(json, "vrf",
+ zl3vni_vrf_name(zl3vni));
+ json_object_string_add(json, "rmac",
+ zl3vni_rmac2str(zl3vni, buf,
+ sizeof(buf)));
+ for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
+ json_object_array_add(json_vni_list,
+ json_object_new_int(zvni->vni));
+ }
+ json_object_object_add(json, "l2-vnis", json_vni_list);
+ }
+}
+
/*
* Print a specific VNI entry.
*/
vty = ctxt[0];
json = ctxt[1];
- if (json == NULL)
+ if (json == NULL) {
vty_out(vty, "VNI: %u\n", zvni->vni);
- else
+ vty_out(vty, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
+ } else {
json_object_int_add(json, "vni", zvni->vni);
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(zvni->vrf_id));
+ }
if (!zvni->vxlan_if) { // unexpected
if (json == NULL)
}
}
+/* print a L3 VNI hash entry */
+static void zl3vni_print_hash(struct hash_backet *backet,
+ void *ctx[])
+{
+ char buf[ETHER_ADDR_STRLEN];
+ struct vty *vty = NULL;
+ json_object *json = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+
+ vty = ctx[0];
+ json = ctx[1];
+
+ zl3vni = (zebra_l3vni_t *)backet->data;
+ if (!zl3vni)
+ return;
+
+ if (!json) {
+ vty_out(vty, "%-10u %-20s %-20s %-5s %-37s %-18s\n",
+ zl3vni->vni,
+ zl3vni_vxlan_if_name(zl3vni),
+ zl3vni_svi_if_name(zl3vni),
+ zl3vni_state2str(zl3vni),
+ zl3vni_vrf_name(zl3vni),
+ zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+ } else {
+ json_object_int_add(json, "vni", zl3vni->vni);
+ json_object_string_add(json, "vxlan-if",
+ zl3vni_vxlan_if_name(zl3vni));
+ json_object_string_add(json, "svi-if",
+ zl3vni_svi_if_name(zl3vni));
+ json_object_string_add(json, "state",
+ zl3vni_state2str(zl3vni));
+ json_object_string_add(json, "vrf",
+ zl3vni_vrf_name(zl3vni));
+ json_object_string_add(json, "rmac",
+ zl3vni_rmac2str(zl3vni, buf,
+ sizeof(buf)));
+ }
+
+}
+
/*
* Print a VNI hash entry - called for display of all VNIs.
*/
num_macs = num_valid_macs(zvni);
num_neigh = hashcount(zvni->neigh_table);
if (json == NULL)
- vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni,
+ vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u %-37s\n",
+ zvni->vni,
zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
- num_vteps);
+ num_vteps,
+ vrf_id_to_name(zvni->vrf_id));
else {
char vni_str[VNI_STR_LEN];
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
struct ipaddr *ip, u_char flags,
u_int16_t cmd)
{
- struct zserv *client;
- struct stream *s;
- int ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
+ int ipa_len;
+ struct zserv *client = NULL;
+ struct stream *s = NULL;
client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
/* BGP may not be running. */
stream_putc(s, flags); /* sticky mac/gateway mac */
+
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s",
+ "Send MACIP %s flags 0x%x MAC %s IP %s L2-VNI %u to %s",
(cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
flags, prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), vni,
if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "neigh %s (MAC %s) on VNI %u is now ACTIVE",
+ "neigh %s (MAC %s) on L2-VNI %u is now ACTIVE",
ipaddr2str(&n->ip, buf2,
sizeof(buf2)),
prefix_mac2str(&n->emac, buf,
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "neigh %s (MAC %s) on VNI %u is now INACTIVE",
+ "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
ipaddr2str(&n->ip, buf2,
sizeof(buf2)),
prefix_mac2str(&n->emac, buf,
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "neigh %s (MAC %s) on VNI %u INACTIVE",
+ "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
ipaddr2str(&n->ip, buf2,
sizeof(buf2)),
prefix_mac2str(&n->emac, buf,
static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
struct ethaddr *macaddr, struct ipaddr *ip)
{
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- zebra_neigh_t *n = NULL;
- zebra_mac_t *mac = NULL;
+ 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)
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) VNI %u, sending GW MAC %s IP %s add to BGP",
+ "SVI %s(%u) L2-VNI %u L3-VNI %u RMAC %s , 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)
{
- zebra_neigh_t *n = NULL;
- zebra_mac_t *mac = NULL;
+ 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 (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
- ifp->name, ifp->ifindex, zvni->vni,
+ "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)),
prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
ipaddr2str(ip, buf2, sizeof(buf2)));
* Map SVI and associated bridge to a VNI. This is invoked upon getting
* neighbor notifications, to see if they are of interest.
*/
-static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if)
+static zebra_vni_t *zvni_from_svi(struct interface *ifp,
+ struct interface *br_if)
{
struct zebra_ns *zns;
struct route_node *rn;
zserv_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 */
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send VNI_ADD %u %s to %s",
+ zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s",
zvni->vni, inet_ntoa(zvni->local_vtep_ip),
+ vrf_id_to_name(zvni->vrf_id),
zebra_route_string(client->proto));
client->vniadd_cnt++;
/* Walk VxLAN interfaces and create VNI hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ vni_t vni;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
- zebra_vni_t *zvni;
- vni_t vni;
ifp = (struct interface *)rn->info;
if (!ifp)
zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
- vxl = &zif->l2info.vxl;
+ vxl = &zif->l2info.vxl;
vni = vxl->vni;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Create VNI hash for intf %s(%u) VNI %u local IP %s",
- ifp->name, ifp->ifindex, vni,
- inet_ntoa(vxl->vtep_ip));
+ if (is_vni_l3(vni)) {
+ zebra_l3vni_t *zl3vni = NULL;
- /* VNI hash entry is not expected to exist. */
- zvni = zvni_lookup(vni);
- if (zvni) {
- zlog_err(
- "VNI hash already present for IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- continue;
- }
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("create L3-VNI hash for Intf %s(%u) L3-VNI %u",
+ ifp->name, ifp->ifindex, vni);
- zvni = zvni_add(vni);
- if (!zvni) {
- zlog_err(
- "Failed to add VNI hash, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return;
- }
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ zlog_err(
+ "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return;
+ }
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->vxlan_if = ifp;
+ /* associate with vxlan_if */
+ zl3vni->vxlan_if = ifp;
- /* Inform BGP if interface is up and mapped to bridge. */
- if (if_is_operative(ifp) && zif->brslave_info.br_if)
- zvni_send_add_to_client(zvni);
+ /* we need to associate with SVI.
+ * we can associate with 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_up(zl3vni);
+
+ } else {
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+ struct interface *vlan_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %s",
+ ifp->name, ifp->ifindex, vni,
+ inet_ntoa(vxl->vtep_ip));
+
+ /* VNI hash entry is not expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (zvni) {
+ zlog_err(
+ "VNI hash already present for IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ continue;
+ }
+
+ zvni = zvni_add(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to add VNI hash, IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return;
+ }
+
+ zvni->local_vtep_ip = vxl->vtep_ip;
+ zvni->vxlan_if = ifp;
+ vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if) {
+ zvni->vrf_id = vlan_if->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+ if (zl3vni)
+ listnode_add_sort(zl3vni->l2vnis, zvni);
+ }
+
+
+ /* Inform BGP if intf is up and mapped to bridge. */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if)
+ zvni_send_add_to_client(zvni);
+ }
}
}
*/
static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
{
- zebra_vni_t *zvni;
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
zvni = (zebra_vni_t *)backet->data;
if (!zvni)
return;
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zvni);
+
/* Free up all neighbors and MACs, if any. */
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
zvni_del(zvni);
}
+/*
+ * Look up MAC hash entry.
+ */
+/*static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac)
+{
+ zebra_mac_t tmp;
+ zebra_mac_t *pmac;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp.macaddr, rmac, ETH_ALEN);
+ pmac = hash_lookup(zl3vni->rmac_table, &tmp);
-/* Public functions */
+ return pmac;
+}*/
/*
- * Display Neighbors for a VNI (VTY command handler).
+ * Callback to allocate RMAC hash entry.
*/
-void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
- vni_t vni, u_char use_json)
+/*static void *zl3vni_rmac_alloc(void *p)
{
- zebra_vni_t *zvni;
- u_int32_t num_neigh;
- struct neigh_walk_ctx wctx;
- json_object *json = NULL;
+ const zebra_mac_t *tmp_rmac = p;
+ zebra_mac_t *zrmac;
- if (!is_evpn_enabled())
- return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% VNI %u does not exist\n", vni);
- return;
- }
- num_neigh = hashcount(zvni->neigh_table);
- if (!num_neigh)
- return;
+ zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
+ *zrmac = *tmp_rmac;
- if (use_json)
- json = json_object_new_object();
+ return ((void *)zrmac);
+}*/
- /* Since we have IPv6 addresses to deal with which can vary widely in
- * size, we try to be a bit more elegant in display by first computing
- * the maximum width.
- */
- memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
- wctx.vty = vty;
- wctx.addr_width = 15;
- wctx.json = json;
- hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+/*
+ * Add RMAC entry to l3-vni
+ */
+/*static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac)
+{
+ zebra_mac_t tmp_rmac;
+ zebra_mac_t *zrmac = NULL;
- if (!use_json) {
- 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");
- } else
- json_object_int_add(json, "numArpNd", num_neigh);
+ memset(&tmp_rmac, 0, sizeof(zebra_mac_t));
+ memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN);
+ zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
+ assert(zrmac);
- hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
- if (use_json) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
-}
+ zrmac->neigh_list = list_new();
+ zrmac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp;
+
+ return zrmac;
+}*/
/*
- * Display neighbors across all VNIs (VTY command handler).
+ * Delete MAC entry.
*/
-void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
- u_char use_json)
+/*static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni,
+ zebra_mac_t *zrmac)
{
- json_object *json = NULL;
- void *args[2];
+ zebra_mac_t *tmp_rmac;
- if (!is_evpn_enabled())
- return;
+ list_delete(zrmac->neigh_list);
- if (use_json)
- json = json_object_new_object();
+ tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
+ if (tmp_rmac)
+ XFREE(MTYPE_MAC, tmp_rmac);
- args[0] = vty;
- args[1] = json;
- hash_iterate(zvrf->vni_table,
- (void (*)(struct hash_backet *,
- void *))zvni_print_neigh_hash_all_vni,
- args);
- if (use_json) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
-}
+ return 0;
+}*/
/*
- * Display specific neighbor for a VNI, if present (VTY command handler).
+ * Install remote RMAC into the kernel.
*/
-void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
- struct zebra_vrf *zvrf, vni_t vni,
- struct ipaddr *ip, u_char use_json)
+/*static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni,
+ zebra_mac_t *zrmac)
{
- zebra_vni_t *zvni;
- zebra_neigh_t *n;
- json_object *json = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
- if (!is_evpn_enabled())
- return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
- if (use_json)
+ if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) ||
+ !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
+ return 0;
+
+ zif = zl3vni->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ return kernel_add_mac(zl3vni->vxlan_if, vxl->access_vlan,
+ &zrmac->macaddr,
+ zrmac->fwd_info.r_vtep_ip, 0);
+}*/
+
+/*
+ * Uninstall remote RMAC from the kernel.
+ */
+/*static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni,
+ zebra_mac_t *zrmac)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
+
+ if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) ||
+ !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
+ return 0;
+
+ if (!zl3vni->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;
+ }
+
+ zif = zl3vni->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan,
+ &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0);
+}*/
+
+/*
+ * Look up nh hash entry on a l3-vni.
+ */
+/*static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+ struct ipaddr *ip)
+{
+ zebra_neigh_t tmp;
+ zebra_neigh_t *n;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
+ n = hash_lookup(zl3vni->nh_table, &tmp);
+
+ return n;
+}*/
+
+
+/*
+ * Callback to allocate NH hash entry on L3-VNI.
+ */
+/*static void *zl3vni_nh_alloc(void *p)
+{
+ const zebra_neigh_t *tmp_n = p;
+ zebra_neigh_t *n;
+
+ n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
+ *n = *tmp_n;
+
+ return ((void *)n);
+}*/
+
+/*
+ * Add neighbor entry.
+ */
+/*static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+ struct ipaddr *ip,
+ struct ethaddr *mac)
+{
+ zebra_neigh_t tmp_n;
+ zebra_neigh_t *n = NULL;
+
+ memset(&tmp_n, 0, sizeof(zebra_neigh_t));
+ memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
+ n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+ assert(n);
+
+ memcpy(&n->emac, mac, ETH_ALEN);
+
+ return n;
+}*/
+
+/*
+ * Delete neighbor entry.
+ */
+/*static int zl3vni_nh_del(zebra_l3vni_t *zl3vni,
+ zebra_neigh_t *n)
+{
+ zebra_neigh_t *tmp_n;
+
+ tmp_n = hash_release(zl3vni->nh_table, n);
+ if (tmp_n)
+ XFREE(MTYPE_NEIGH, tmp_n);
+
+ return 0;
+}*/
+
+/*
+ * Install remote nh as neigh into the kernel.
+ */
+/*static int zl3vni_nh_install(zebra_l3vni_t *zl3vni,
+ zebra_neigh_t *n)
+{
+ if (!is_l3vni_oper_up(zl3vni))
+ return -1;
+
+ if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
+ !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
+ return 0;
+
+ return kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac);
+}*/
+
+/*
+ * Uninstall remote nh from the kernel.
+ */
+/*static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni,
+ zebra_neigh_t *n)
+{
+ if (!is_l3vni_oper_up(zl3vni))
+ return -1;
+
+ if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
+ !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
+ return 0;
+
+ return kernel_del_neigh(zl3vni->svi_if, &n->ip);
+}*/
+
+/*
+ * Hash function for L3 VNI.
+ */
+static unsigned int l3vni_hash_keymake(void *p)
+{
+ const zebra_l3vni_t *zl3vni = p;
+
+ return jhash_1word(zl3vni->vni, 0);
+}
+
+/*
+ * Compare 2 L3 VNI hash entries.
+ */
+static int l3vni_hash_cmp(const void *p1, const void *p2)
+{
+ const zebra_l3vni_t *zl3vni1 = p1;
+ const zebra_l3vni_t *zl3vni2 = p2;
+
+ return (zl3vni1->vni == zl3vni2->vni);
+}
+
+/*
+ * Callback to allocate L3 VNI hash entry.
+ */
+static void *zl3vni_alloc(void *p)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ const zebra_l3vni_t *tmp_l3vni = p;
+
+ zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t));
+ zl3vni->vni = tmp_l3vni->vni;
+ return ((void *)zl3vni);
+}
+
+/*
+ * Look up L3 VNI hash entry.
+ */
+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);
+
+ return zl3vni;
+}
+
+/*
+ * Add L3 VNI hash entry.
+ */
+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);
+ 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;
+
+ /* Create hash table for remote RMAC */
+ zl3vni->rmac_table =
+ hash_create(mac_hash_keymake, mac_cmp,
+ "Zebra L3-VNI RMAC-Table");
+
+ /* Create hash table for neighbors */
+ zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp,
+ "Zebra L3-VNI next-hop table");
+
+ return zl3vni;
+}
+
+/*
+ * Delete L3 VNI hash entry.
+ */
+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);
+ zl3vni->l2vnis = NULL;
+
+ /* Free the rmac table */
+ hash_free(zl3vni->rmac_table);
+ zl3vni->rmac_table = NULL;
+
+ /* Free the nh table */
+ hash_free(zl3vni->nh_table);
+ zl3vni->nh_table = NULL;
+
+ /* Free the VNI hash entry and allocated memory. */
+ tmp_zl3vni = hash_release(zns->l3vni_table, zl3vni);
+ if (tmp_zl3vni)
+ XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
+
+ return 0;
+}
+
+static int is_vni_l3(vni_t vni)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni)
+ return 1;
+ return 0;
+}
+
+static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+{
+ struct zebra_ns *zns = NULL;
+ struct route_node *rn = NULL;
+ struct interface *ifp = NULL;
+
+ /* loop through all vxlan-interface */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
+
+ ifp = (struct interface *)rn->info;
+ if (!ifp)
+ continue;
+
+ zif = ifp->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+
+ vxl = &zif->l2info.vxl;
+ if (vxl->vni == zl3vni->vni)
+ return ifp;
+ }
+
+ return NULL;
+}
+
+static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
+{
+ struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
+ struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
+
+ if (!zl3vni->vxlan_if)
+ return NULL;
+
+ zif = zl3vni->vxlan_if->info;
+ if (!zif)
+ return NULL;
+
+ vxl = &zif->l2info.vxl;
+
+ return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+}
+
+static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id)
+{
+ struct zebra_vrf *zvrf = NULL;
+
+ zvrf = zebra_vrf_lookup_by_id(vrf_id);
+ if (!zvrf)
+ return NULL;
+
+ return zl3vni_lookup(zvrf->l3vni);
+}
+
+/*
+ * Map SVI and associated bridge to a VNI. This is invoked upon getting
+ * neighbor notifications, to see if they are of interest.
+ */
+static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
+ struct interface *br_if)
+{
+ int found = 0;
+ vlanid_t vid = 0;
+ u_char bridge_vlan_aware = 0;
+ zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_ns *zns = NULL;
+ struct route_node *rn = NULL;
+ struct zebra_if *zif = NULL;
+ struct interface *tmp_if = NULL;
+ struct zebra_l2info_bridge *br = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
+
+ if (!br_if)
+ return NULL;
+
+ /* Make sure the linked interface is a bridge. */
+ if (!IS_ZEBRA_IF_BRIDGE(br_if))
+ return NULL;
+
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
+ assert(zif);
+ br = &zif->l2info.br;
+ bridge_vlan_aware = br->vlan_aware;
+ if (bridge_vlan_aware) {
+ struct zebra_l2info_vlan *vl;
+
+ if (!IS_ZEBRA_IF_VLAN(ifp))
+ return NULL;
+
+ zif = ifp->info;
+ assert(zif);
+ vl = &zif->l2info.vl;
+ vid = vl->vid;
+ }
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ zl3vni = zl3vni_lookup(vxl->vni);
+ return zl3vni;
+}
+
+/*
+ * Inform BGP about l3-vni.
+ */
+static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni)
+{
+ struct stream *s = NULL;
+ struct zserv *client = NULL;
+ struct ethaddr rmac;
+ char buf[ETHER_ADDR_STRLEN];
+
+ client = zebra_find_client(ZEBRA_ROUTE_BGP);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ /* get the rmac */
+ memset(&rmac, 0, sizeof(struct ethaddr));
+ zl3vni_get_rmac(zl3vni, &rmac);
+
+ s = client->obuf;
+ stream_reset(s);
+
+ zserv_create_header(s, ZEBRA_L3VNI_ADD,
+ zl3vni_vrf_id(zl3vni));
+ stream_putl(s, zl3vni->vni);
+ stream_put(s, &rmac, sizeof(struct ethaddr));
+
+ /* 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",
+ zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
+ prefix_mac2str(&rmac, buf, sizeof(buf)),
+ zebra_route_string(client->proto));
+
+ client->l3vniadd_cnt++;
+ return zebra_server_send_message(client);
+}
+
+/*
+ * Inform BGP about local l3-VNI deletion.
+ */
+static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni)
+{
+ struct stream *s = NULL;
+ struct zserv *client = NULL;
+
+ client = zebra_find_client(ZEBRA_ROUTE_BGP);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ s = client->obuf;
+ stream_reset(s);
+
+ zserv_create_header(s, ZEBRA_L3VNI_DEL,
+ zl3vni_vrf_id(zl3vni));
+ stream_putl(s, zl3vni->vni);
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Send L3_VNI_DEL %u VRF %s to %s",
+ zl3vni->vni,
+ vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
+ zebra_route_string(client->proto));
+
+ client->l3vnidel_cnt++;
+ return zebra_server_send_message(client);
+}
+
+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",
+ zl3vni->vni);
+
+ /* send l3vni add to BGP */
+ zl3vni_send_add_to_client(zl3vni);
+}
+
+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",
+ zl3vni->vni);
+
+ /* send l3-vni del to BGP*/
+ zl3vni_send_del_to_client(zl3vni);
+}
+
+static void zvni_add_to_l3vni_list(struct hash_backet *backet,
+ void *ctxt)
+{
+ zebra_vni_t *zvni = (zebra_vni_t *) backet->data;
+ zebra_l3vni_t *zl3vni = (zebra_l3vni_t *) ctxt;
+
+ if (zvni->vrf_id == zl3vni_vrf_id(zl3vni))
+ 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
+ */
+static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf,
+ vni_t vni, int add)
+{
+ zebra_vni_t *zvni = NULL;
+
+ /* There is a possibility that VNI notification was already received
+ * from kernel and we programmed it as L2-VNI
+ * In such a case we need to delete this L2-VNI first, so
+ * 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 */
+ if (add) {
+ /* Locate hash entry */
+ zvni = zvni_lookup(vni);
+ if (!zvni)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del L2-VNI %u - transition to L3-VNI",
+ vni);
+
+ /* Delete VNI from BGP. */
+ zvni_send_del_to_client(zvni->vni);
+
+ /* Free up all neighbors and MAC, if any. */
+ zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
+ zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zvni_vtep_del_all(zvni, 0);
+
+ /* Delete the hash entry. */
+ if (zvni_del(zvni)) {
+ zlog_err("Failed to del VNI hash %p, VNI %u",
+ zvni, zvni->vni);
+ return -1;
+ }
+ } else {
+ /* 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 */
+ }
+
+ return 0;
+}
+
+/* Public functions */
+
+void zebra_vxlan_print_rmacs_l3vni(struct vty *vty,
+ vni_t l3vni,
+ u_char use_json)
+{
+ zebra_l3vni_t *zl3vni;
+ u_int32_t num_rmacs;
+ struct rmac_walk_ctx wctx;
+ json_object *json = NULL;
+ json_object *json_rmac = NULL;
+
+ if (!is_evpn_enabled())
+ return;
+
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+ return;
+ }
+ num_rmacs = hashcount(zl3vni->rmac_table);
+ if (!num_rmacs)
+ return;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_rmac = json_object_new_array();
+ }
+
+ memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
+ wctx.vty = vty;
+ wctx.json = json_rmac;
+
+ if (!use_json) {
+ vty_out(vty,
+ "Number of Remote RMACs known for this VNI: %u\n",
+ num_rmacs);
+ vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
+ "Remote VTEP", "Refcnt");
+ } else
+ json_object_int_add(json, "numRmacs", num_rmacs);
+
+ hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
+
+ if (use_json) {
+ json_object_object_add(json, "rmacs", json_rmac);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty,
+ u_char use_json)
+{
+ struct zebra_ns *zns = NULL;
+ struct rmac_walk_ctx wctx;
+ json_object *json = NULL;
+
+ if (!is_evpn_enabled()) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ if (!zns)
+ return;
+
+ if (use_json)
+ json = json_object_new_object();
+
+ memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
+ wctx.vty = vty;
+ wctx.json = json;
+
+ hash_iterate(zns->l3vni_table, zl3vni_print_rmac_hash_all_vni, &wctx);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+void zebra_vxlan_print_nh_l3vni(struct vty *vty,
+ vni_t l3vni,
+ u_char use_json)
+{
+ u_int32_t num_nh;
+ struct nh_walk_ctx *wctx;
+ json_object *json = NULL;
+ json_object *json_nh = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (!is_evpn_enabled())
+ return;
+
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+ return;
+ }
+
+ num_nh = hashcount(zl3vni->nh_table);
+ if (!num_nh)
+ return;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_nh = json_object_new_array();
+ }
+
+ wctx->vty = vty;
+ wctx->json = json_nh;
+
+ if (!use_json) {
+ vty_out(vty,
+ "Number of NH Neighbors known for this VNI: %u\n",
+ num_nh);
+ vty_out(vty, "%15s %-17s %6s\n", "IP",
+ "RMAC", "Refcnt");
+ } else
+ json_object_int_add(json, "numNh", num_nh);
+
+ hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+
+ if (use_json) {
+ json_object_object_add(json, "next-hop-neighbors", json_nh);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+void zebra_vxlan_print_nh_all_l3vni(struct vty *vty,
+ u_char use_json)
+{
+ return;
+}
+
+/*
+ * Display L3 VNI information (VTY command handler).
+ */
+void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json)
+{
+ void *args[2];
+ json_object *json = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+
+ args[0] = vty;
+ args[1] = json;
+
+ if (!is_evpn_enabled())
+ return;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
+ return;
+ }
+
+ if (use_json)
+ json = json_object_new_object();
+
+ zl3vni_print(zl3vni, (void *)args);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+/*
+ * Display L3 VNI hash table (VTY command handler).
+ */
+void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json)
+{
+ u_int32_t num_vnis;
+ void *args[2];
+ json_object *json = NULL;
+ struct zebra_ns *zns = NULL;
+
+ args[0] = vty;
+ args[1] = json;
+
+ if (!is_evpn_enabled())
+ return;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ assert(zns);
+
+ num_vnis = hashcount(zns->l3vni_table);
+ if (!num_vnis) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ if (use_json) {
+ json = json_object_new_object();
+ 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");
+ }
+
+ hash_iterate(zns->l3vni_table,
+ (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
+ args);
+
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+/*
+ * Display Neighbors for a VNI (VTY command handler).
+ */
+void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
+ vni_t vni, u_char use_json)
+{
+ zebra_vni_t *zvni;
+ u_int32_t num_neigh;
+ struct neigh_walk_ctx wctx;
+ json_object *json = NULL;
+
+ if (!is_evpn_enabled())
+ return;
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
+ return;
+ }
+ num_neigh = hashcount(zvni->neigh_table);
+ if (!num_neigh)
+ return;
+
+ if (use_json)
+ json = json_object_new_object();
+
+ /* Since we have IPv6 addresses to deal with which can vary widely in
+ * size, we try to be a bit more elegant in display by first computing
+ * the maximum width.
+ */
+ memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+ wctx.zvni = zvni;
+ wctx.vty = vty;
+ wctx.addr_width = 15;
+ wctx.json = json;
+ hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+
+ if (!use_json) {
+ 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");
+ } else
+ json_object_int_add(json, "numArpNd", num_neigh);
+
+ hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+/*
+ * Display neighbors across all VNIs (VTY command handler).
+ */
+void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
+{
+ json_object *json = NULL;
+ void *args[2];
+
+ if (!is_evpn_enabled())
+ return;
+
+ if (use_json)
+ json = json_object_new_object();
+
+ args[0] = vty;
+ args[1] = json;
+ hash_iterate(zvrf->vni_table,
+ (void (*)(struct hash_backet *,
+ void *))zvni_print_neigh_hash_all_vni,
+ args);
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+/*
+ * Display specific neighbor for a VNI, if present (VTY command handler).
+ */
+void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
+ struct zebra_vrf *zvrf, vni_t vni,
+ struct ipaddr *ip, u_char use_json)
+{
+ zebra_vni_t *zvni;
+ zebra_neigh_t *n;
+ json_object *json = NULL;
+
+ if (!is_evpn_enabled())
+ return;
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
vty_out(vty, "Advertise gateway mac-ip: %s\n",
zvrf->advertise_gw_macip ? "Yes" : "No");
vty_out(vty, "Number of VNIs: %u\n", num_vnis);
- vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI",
+ vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s %-37s\n", "VNI",
"VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
- "# Remote VTEPs");
+ "# Remote VTEPs", "VRF");
}
args[0] = vty;
args[1] = json;
int zebra_vxlan_local_neigh_del(struct interface *ifp,
struct interface *link_if, struct ipaddr *ip)
{
- zebra_vni_t *zvni;
- zebra_neigh_t *n;
+ vni_t l3vni = 0;
+ struct ethaddr rmac;
char buf[INET6_ADDRSTRLEN];
+ char buf1[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
- zebra_mac_t *zmac;
+ zebra_neigh_t *n = NULL;
+ zebra_vni_t *zvni = NULL;
+ zebra_mac_t *zmac = NULL;
+
+ memset(&rmac, 0, sizeof(struct ethaddr));
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
*/
- zvni = zvni_map_svi(ifp, link_if);
+ zvni = zvni_from_svi(ifp, link_if);
if (!zvni)
return 0;
if (!zvni->vxlan_if) {
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) -> VNI %u",
+ zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u L3-VNI %u RMAC %s",
ipaddr2str(ip, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni);
+ ifp->name, ifp->ifindex, zvni->vni,
+ l3vni, prefix_mac2str(&rmac, buf1, sizeof(buf1)));
/* 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)
{
- zebra_vni_t *zvni;
- zebra_neigh_t *n;
- zebra_mac_t *zmac, *old_zmac;
+ 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;
+
+ memset(&rmac, 0, sizeof(struct ethaddr));
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
*/
- zvni = zvni_map_svi(ifp, link_if);
+ zvni = zvni_from_svi(ifp, link_if);
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-> VNI %u",
+ "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u L3-VNI %u RMAC %s",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
- zvni->vni);
+ zvni->vni, l3vni,
+ prefix_mac2str(&rmac, buf1, sizeof(buf1)));
/* 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 VNI %u",
+ zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u L3-VNI %u with RMAC %s",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
+ zvni->vni,
+ l3vni,
+ prefix_mac2str(&rmac, buf1, sizeof(buf1)));
ZEBRA_NEIGH_SET_ACTIVE(n);
+
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
}
struct stream *s;
vni_t vni;
struct ethaddr macaddr;
+ struct ethaddr rmac;
struct ipaddr ip;
struct in_addr vtep_ip;
zebra_vni_t *zvni;
u_short l = 0, ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
+ char buf3[INET6_ADDRSTRLEN];
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
+ memset(&macaddr, 0, sizeof(struct ethaddr));
+ memset(&rmac, 0, sizeof(struct ethaddr));
+ memset(&ip, 0, sizeof(struct ipaddr));
+ memset(&vtep_ip, 0, sizeof(struct in_addr));
+
s = client->ibuf;
while (l < length) {
l += 4 + ETH_ALEN + 4 + ipa_len;
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
l += IPV4_MAX_BYTELEN;
+ stream_get(&rmac.octet, s, ETH_ALEN);
+ l += 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 MAC %s IP %s VNI %u Remote VTEP %s RMAC %s from %s",
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
inet_ntoa(vtep_ip),
+ prefix_mac2str(&rmac, buf3, sizeof(buf3)),
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
struct stream *s;
vni_t vni;
struct ethaddr macaddr;
+ struct ethaddr rmac;
struct ipaddr ip;
struct in_addr vtep_ip;
zebra_vni_t *zvni;
int update_mac = 0, update_neigh = 0;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
u_char sticky;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
+ memset(&macaddr, 0, sizeof(struct ethaddr));
+ memset(&rmac, 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__);
STREAM_GETC(s, sticky);
l++;
+ /* Get router mac */
+ stream_get(&rmac.octet, s, ETH_ALEN);
+ l += ETH_ALEN;
+
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
+ "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s RMAC %s from %s",
sticky ? "sticky " : "",
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
inet_ntoa(vtep_ip),
+ prefix_mac2str(&rmac, buf2, sizeof(buf2)),
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
svi_if_link = if_lookup_by_index_per_ns(
zebra_ns_lookup(NS_DEFAULT),
svi_if_zif->link_ifindex);
- zvni = zvni_map_svi(svi_if, svi_if_link);
+ zvni = zvni_from_svi(svi_if, svi_if_link);
}
} else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
/*
* If it is a vlan unaware bridge then svi is the bridge
* itself
*/
- zvni = zvni_map_svi(svi_if, svi_if);
+ zvni = zvni_from_svi(svi_if, svi_if);
}
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_if *svi_if_zif =
svi_if_link = if_lookup_by_index_per_ns(
zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex);
if (svi_if_zif && svi_if_link)
- zvni = zvni_map_svi(ifp, svi_if_link);
+ zvni = zvni_from_svi(ifp, svi_if_link);
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
- zvni = zvni_map_svi(ifp, ifp);
+ zvni = zvni_from_svi(ifp, ifp);
}
if (!zvni)
}
/*
- * Handle SVI interface going down. At this point, this is a NOP since
- * the kernel deletes the neighbor entries on this SVI (if any).
+ * Handle SVI interface going down.
+ * SVI can be associated to either L3-VNI or L2-VNI.
+ * For L2-VNI: At this point, this is a NOP since
+ * the kernel deletes the neighbor entries on this SVI (if any).
+ * We only need to update the vrf corresponding to zvni.
+ * For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete
+ * from bgp
*/
int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_svi(ifp, link_if);
+ if (zl3vni) {
+
+ /* process l3-vni down */
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+ /* remove association with svi-if */
+ zl3vni->svi_if = NULL;
+ } else {
+ zebra_vni_t *zvni = NULL;
+
+ /* since we dont have svi corresponding to zvni, we associate it
+ * to default vrf. Note: the corresponding neigh entries on the
+ * SVI would have already been deleted */
+ zvni = zvni_from_svi(ifp, link_if);
+ if (zvni) {
+ zvni->vrf_id = VRF_DEFAULT;
+
+ /* update the tenant vrf in BGP */
+ zvni_send_add_to_client(zvni);
+ }
+ }
return 0;
}
/*
- * Handle SVI interface coming up. This may or may not be of interest,
- * but if this is a SVI on a VxLAN bridge, we need to install any remote
- * neighbor entries (which will be used for EVPN ARP suppression).
+ * Handle SVI interface coming up.
+ * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni
+ * vxlan intf).
+ * For L2-VNI: we need to install any remote neighbors entried (used for
+ * apr-suppression)
+ * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI
*/
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
{
- zebra_vni_t *zvni;
- struct neigh_walk_ctx n_wctx;
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
- zvni = zvni_map_svi(ifp, link_if);
- if (!zvni)
- return 0;
+ zl3vni = zl3vni_from_svi(ifp, link_if);
+ if (zl3vni) {
- if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
- zvni->vni, zvni);
- return -1;
- }
+ /* associate with svi */
+ zl3vni->svi_if = ifp;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("SVI %s(%u) VNI %u is UP, installing neighbors",
- ifp->name, ifp->ifindex, zvni->vni);
+ /* process oper-up */
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ } else {
+
+ /* process SVI up for l2-vni */
+ struct neigh_walk_ctx n_wctx;
+
+ 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 SVI up",
+ zvni->vni, zvni);
+ return -1;
+ }
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("SVI %s(%u) VNI %u VRF %s is UP, installing neighbors",
+ ifp->name, ifp->ifindex, zvni->vni,
+ vrf_id_to_name(ifp->vrf_id));
- /* Install any remote neighbors for this VNI. */
- memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
- hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx);
+ /* update the vrf information for l2-vni and inform bgp */
+ zvni->vrf_id = ifp->vrf_id;
+ zvni_send_add_to_client(zvni);
+
+ /* Install any remote neighbors for this VNI. */
+ memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
+ n_wctx.zvni = zvni;
+ hash_iterate(zvni->neigh_table,
+ zvni_install_neigh_hash,
+ &n_wctx);
+ }
return 0;
}
/*
- * Handle VxLAN interface down - update BGP if required, and do
- * internal cleanup.
+ * Handle VxLAN interface down
*/
int zebra_vxlan_if_down(struct interface *ifp)
{
- struct zebra_if *zif;
- zebra_vni_t *zvni;
- struct zebra_l2info_vxlan *vxl;
vni_t vni;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) VNI %u is DOWN",
- ifp->name, ifp->ifindex, vni);
- /* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_err(
- "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
+ if (is_vni_l3(vni)) {
+
+ /* process-if-down for l3-vni */
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L3-VNI %u is DOWN",
+ ifp->name, ifp->ifindex, vni);
+
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ zlog_err(
+ "Failed to locate L3-VNI hash at DOWN, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+ } else {
+ /* process if-down for l2-vni */
+ zebra_vni_t *zvni;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L2-VNI %u is DOWN",
+ ifp->name, ifp->ifindex, vni);
- assert(zvni->vxlan_if == ifp);
+ /* Locate hash entry; it is expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
- /* Delete this VNI from BGP. */
- zvni_send_del_to_client(zvni->vni);
+ assert(zvni->vxlan_if == ifp);
- /* Free up all neighbors and MACs, if any. */
- zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+ /* Delete this VNI from BGP. */
+ zvni_send_del_to_client(zvni->vni);
- /* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 1);
+ /* Free up all neighbors and MACs, if any. */
+ zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
+ zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+ /* Free up all remote VTEPs, if any. */
+ zvni_vtep_del_all(zvni, 1);
+ }
return 0;
}
*/
int zebra_vxlan_if_up(struct interface *ifp)
{
- struct zebra_if *zif;
- zebra_vni_t *zvni;
- struct zebra_l2info_vxlan *vxl;
vni_t vni;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) VNI %u is UP",
- ifp->name, ifp->ifindex, vni);
+ if (is_vni_l3(vni)) {
- /* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_err(
- "Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
+ /* Handle L3-VNI add */
+ zebra_l3vni_t *zl3vni = NULL;
- assert(zvni->vxlan_if == ifp);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L3-VNI %u is UP",
+ ifp->name, ifp->ifindex, vni);
- /* If part of a bridge, inform BGP about this VNI. */
- /* Also, read and populate local MACs and neighbors. */
- if (zif->brslave_info.br_if) {
- zvni_send_add_to_client(zvni);
- zvni_read_mac_neigh(zvni, ifp);
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ zlog_err(
+ "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ /* we need to associate with SVI, if any, we can associate with
+ * 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_up(zl3vni);
+ } else {
+ /* Handle L2-VNI add */
+
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+ struct interface *vlan_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L2-VNI %u is UP",
+ ifp->name, ifp->ifindex, vni);
+
+ /* Locate hash entry; it is expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ assert(zvni->vxlan_if == ifp);
+ vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if) {
+ zvni->vrf_id = vlan_if->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+ if (zl3vni)
+ listnode_add_sort(zl3vni->l2vnis, zvni);
+ }
+
+ /* If part of a bridge, inform BGP about this VNI. */
+ /* Also, read and populate local MACs and neighbors. */
+ if (zif->brslave_info.br_if) {
+ zvni_send_add_to_client(zvni);
+ zvni_read_mac_neigh(zvni, ifp);
+ }
}
return 0;
*/
int zebra_vxlan_if_del(struct interface *ifp)
{
- struct zebra_if *zif;
- zebra_vni_t *zvni;
- struct zebra_l2info_vxlan *vxl;
vni_t vni;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del VNI %u intf %s(%u)",
- vni, ifp->name, ifp->ifindex);
+ if (is_vni_l3(vni)) {
- /* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_err(
- "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return 0;
- }
+ /* process if-del for l3-vni */
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del L3-VNI %u intf %s(%u)",
+ vni, ifp->name, ifp->ifindex);
- /* Delete VNI from BGP. */
- zvni_send_del_to_client(zvni->vni);
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ zlog_err(
+ "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
- /* Free up all neighbors and MAC, if any. */
- zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+ /* process oper-down for l3-vni */
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
- /* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 0);
+ /* remove the association with vxlan_if */
+ zl3vni->vxlan_if = NULL;
+ } else {
- /* Delete the hash entry. */
- if (zvni_del(zvni)) {
- zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
- zvni, ifp->name, ifp->ifindex, zvni->vni);
- return -1;
+ /* process if-del for l2-vni*/
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del L2-VNI %u intf %s(%u)",
+ vni, ifp->name, ifp->ifindex);
+
+ /* Locate hash entry; it is expected to exist. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
+
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zvni);
+
+ /* Delete VNI from BGP. */
+ zvni_send_del_to_client(zvni->vni);
+
+ /* Free up all neighbors and MAC, if any. */
+ zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
+ zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zvni_vtep_del_all(zvni, 0);
+
+ /* Delete the hash entry. */
+ if (zvni_del(zvni)) {
+ zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
+ zvni, ifp->name, ifp->ifindex, zvni->vni);
+ return -1;
+ }
}
return 0;
*/
int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
{
- struct zebra_if *zif;
- zebra_vni_t *zvni;
- struct zebra_l2info_vxlan *vxl;
vni_t vni;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- /* Update VNI hash. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_err(
- "Failed to find VNI hash on update, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
+ if (is_vni_l3(vni)) {
+ zebra_l3vni_t *zl3vni = NULL;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Update VNI %u intf %s(%u) VLAN %u local IP %s "
- "master %u chg 0x%x",
- vni, ifp->name, ifp->ifindex,
- vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
- zif->brslave_info.bridge_ifindex, chgflags);
-
- /* Removed from bridge? Cleanup and return */
- if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
- /* Delete from client, remove all remote VTEPs */
- /* Also, free up all MACs and neighbors. */
- zvni_send_del_to_client(zvni->vni);
- zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
- zvni_vtep_del_all(zvni, 1);
- return 0;
- }
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ zlog_err(
+ "Failed to find L3-VNI hash on update, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
- /* Handle other changes. */
- if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- /* Remove all existing local neighbors and MACs for this VNI
- * (including from BGP)
- */
- zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
- zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
- }
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Update L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
+ vni, ifp->name, ifp->ifindex,
+ vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+ zif->brslave_info.bridge_ifindex, chgflags);
+
+ /* Removed from bridge? Cleanup and return */
+ if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+ && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ return 0;
+ }
+
+ /* access-vlan change - process oper down, associate with new
+ * 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);
+ zl3vni->svi_if = NULL;
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(
+ zl3vni);
+ }
+ }
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->vxlan_if = ifp;
+ /* if we have a valid new master, process l3-vni oper up */
+ if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ }
+ } else {
+ zebra_vni_t *zvni = NULL;
- /* Take further actions needed. Note that if we are here, there is a
- * change of interest.
- */
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return 0;
+ /* Update VNI hash. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to find L2-VNI hash on update, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
- /* Inform BGP, if there is a change of interest. */
- if (chgflags
- & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
- zvni_send_add_to_client(zvni);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Update L2-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
+ vni, ifp->name, ifp->ifindex,
+ vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+ zif->brslave_info.bridge_ifindex, chgflags);
+
+ /* Removed from bridge? Cleanup and return */
+ if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+ && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+ /* Delete from client, remove all remote VTEPs */
+ /* Also, free up all MACs and neighbors. */
+ zvni_send_del_to_client(zvni->vni);
+ zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
+ zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+ zvni_vtep_del_all(zvni, 1);
+ return 0;
+ }
- /* If there is a valid new master or a VLAN mapping change, read and
- * populate local MACs and neighbors. Also, reinstall any remote MACs
- * and neighbors for this VNI (based on new VLAN).
- */
- if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- zvni_read_mac_neigh(zvni, ifp);
- else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- struct mac_walk_ctx m_wctx;
- struct neigh_walk_ctx n_wctx;
+ /* Handle other changes. */
+ if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ /* Remove all existing local neigh and MACs for this VNI
+ * (including from BGP)
+ */
+ zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+ zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+ }
- zvni_read_mac_neigh(zvni, ifp);
+ zvni->local_vtep_ip = vxl->vtep_ip;
+ zvni->vxlan_if = ifp;
- memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
- m_wctx.zvni = zvni;
- hash_iterate(zvni->mac_table, zvni_install_mac_hash, &m_wctx);
+ /* Take further actions needed.
+ * Note that if we are here, there is a change of interest.
+ */
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
- memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
- hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
- &n_wctx);
+ /* Inform BGP, if there is a change of interest. */
+ if (chgflags
+ & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
+ zvni_send_add_to_client(zvni);
+
+ /* If there is a valid new master or a VLAN mapping change,
+ * read and populate local MACs and neighbors.
+ * Also, reinstall any remote MACs and neighbors
+ * for this VNI (based on new VLAN).
+ */
+ if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+ zvni_read_mac_neigh(zvni, ifp);
+ else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ struct mac_walk_ctx m_wctx;
+ struct neigh_walk_ctx n_wctx;
+
+ zvni_read_mac_neigh(zvni, ifp);
+
+ memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
+ m_wctx.zvni = zvni;
+ hash_iterate(zvni->mac_table,
+ zvni_install_mac_hash,
+ &m_wctx);
+
+ memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
+ n_wctx.zvni = zvni;
+ hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
+ &n_wctx);
+ }
}
return 0;
*/
int zebra_vxlan_if_add(struct interface *ifp)
{
- struct zebra_if *zif;
- zebra_vni_t *zvni;
- struct zebra_l2info_vxlan *vxl;
vni_t vni;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
vxl = &zif->l2info.vxl;
vni = vxl->vni;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Add VNI %u intf %s(%u) VLAN %u local IP %s master %u",
- vni, ifp->name, ifp->ifindex,
- vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
- zif->brslave_info.bridge_ifindex);
+ if (is_vni_l3(vni)) {
- /* Create or update VNI hash. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zvni = zvni_add(vni);
- if (!zvni) {
+ /* process if-add for l3-vni*/
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u",
+ vni, ifp->name, ifp->ifindex,
+ vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+ zif->brslave_info.bridge_ifindex);
+
+ /*
+ * we expect the l3-vni has entry to be present here.
+ * The only place l3-vni is created in zebra is vrf-vni mapping
+ * command. This might change when we have the switchd support
+ * for l3-vxlan interface.
+ */
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
zlog_err(
- "Failed to add VNI hash, IF %s(%u) VNI %u",
+ "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
+
+ /* associate with vxlan_if */
+ zl3vni->vxlan_if = ifp;
+
+ /* Associate with SVI, if any. We can associate with svi-if only
+ * after association with vxlan_if is complete */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ } else {
+
+ /* process if-add for l2-vni */
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+ struct interface *vlan_if = NULL;
+
+ /* Create or update VNI hash. */
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ zvni = zvni_add(vni);
+ if (!zvni) {
+ zlog_err(
+ "Failed to add VNI hash, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+ }
+
+ zvni->local_vtep_ip = vxl->vtep_ip;
+ zvni->vxlan_if = ifp;
+ vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if) {
+ zvni->vrf_id = vlan_if->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+ if (zl3vni)
+ listnode_add_sort(zl3vni->l2vnis, zvni);
+ }
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u",
+ vni,
+ vlan_if ? vrf_id_to_name(vlan_if->vrf_id) :
+ "Default",
+ ifp->name, ifp->ifindex,
+ vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+ zif->brslave_info.bridge_ifindex);
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
+
+ /* Inform BGP */
+ zvni_send_add_to_client(zvni);
+
+ /* Read and populate local MACs and neighbors */
+ zvni_read_mac_neigh(zvni, ifp);
+ }
+
+ return 0;
+}
+
+int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
+ vni_t vni, char *err,
+ int add)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_vrf *zvrf_default = NULL;
+
+ zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+ if (!zvrf_default)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("vrf %s vni %u %s",
+ zvrf_name(zvrf),
+ vni,
+ add ? "ADD" : "DEL");
+
+ if (add) {
+
+ zebra_vxlan_handle_vni_transition(zvrf, vni, add);
+
+ /* check if the vni is already present under zvrf */
+ if (zvrf->l3vni) {
+ 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,
+ "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,
+ "Could not add L3-VNI");
+ return -1;
+ }
+
+ /* associate the vrf with vni */
+ zvrf->l3vni = vni;
+
+ /* associate with vxlan-intf;
+ * 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 */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+ /* formulate l2vni list */
+ hash_iterate(zvrf_default->vni_table,
+ zvni_add_to_l3vni_list, zl3vni);
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+ } else {
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ snprintf(err, ERR_STR_SZ, "VNI doesn't exist");
return -1;
}
+
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+ zvrf->l3vni = 0;
+ zl3vni_del(zl3vni);
+
+ zebra_vxlan_handle_vni_transition(zvrf, vni, add);
}
+ return 0;
+}
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->vxlan_if = ifp;
+int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+{
+ zebra_l3vni_t *zl3vni = NULL;
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ zl3vni = zl3vni_from_vrf(zvrf_id(zvrf));
+ if (!zl3vni)
return 0;
- /* Inform BGP */
- zvni_send_add_to_client(zvni);
-
- /* Read and populate local MACs and neighbors */
- zvni_read_mac_neigh(zvni, ifp);
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ zl3vni_del(zl3vni);
+ zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0);
return 0;
}
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
hash_free(zvrf->vni_table);
}
+
+/* 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");
+}
+
+/* free l3vni table */
+void zebra_vxlan_ns_disable(struct zebra_ns *zns)
+{
+ hash_free(zns->l3vni_table);
+}