2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* Zebra EVPN for VxLAN code
|
|
|
|
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
|
|
|
|
*
|
|
|
|
* This file is part of FRR.
|
|
|
|
*
|
|
|
|
* FRR is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* FRR is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with FRR; see the file COPYING. If not, write to the Free
|
|
|
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "if.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "table.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "jhash.h"
|
|
|
|
#include "vlan.h"
|
|
|
|
#include "vxlan.h"
|
|
|
|
|
|
|
|
#include "zebra/rib.h"
|
|
|
|
#include "zebra/rt.h"
|
|
|
|
#include "zebra/zebra_ns.h"
|
|
|
|
#include "zebra/zserv.h"
|
|
|
|
#include "zebra/debug.h"
|
|
|
|
#include "zebra/interface.h"
|
|
|
|
#include "zebra/zebra_vrf.h"
|
|
|
|
#include "zebra/rt_netlink.h"
|
|
|
|
#include "zebra/zebra_vxlan_private.h"
|
|
|
|
#include "zebra/zebra_vxlan.h"
|
|
|
|
#include "zebra/zebra_memory.h"
|
|
|
|
#include "zebra/zebra_l2.h"
|
2017-06-22 01:37:51 +02:00
|
|
|
#include "lib/json.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
|
2017-05-15 07:38:26 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
|
2017-07-17 14:03:14 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
|
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/* definitions */
|
|
|
|
|
|
|
|
|
|
|
|
/* static function declarations */
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
|
|
|
|
static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
|
2017-06-22 01:37:51 +02:00
|
|
|
void **args);
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt);
|
|
|
|
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);
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print(zebra_vni_t *zvni, void **ctxt);
|
|
|
|
static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_macip_send_msg_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ethaddr *macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ipaddr *ip, u_char flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
u_int16_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);
|
2017-07-06 00:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
|
|
|
|
struct ethaddr *mac);
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
|
|
|
|
static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg);
|
|
|
|
static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip);
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_neigh_del_all(zebra_vni_t *zvni,
|
2017-07-17 14:03:14 +02:00
|
|
|
int uninstall, int upd_client, u_int32_t flags);
|
|
|
|
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_neigh_send_add_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ipaddr *ip,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_neigh_send_del_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ipaddr *ip,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
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,
|
|
|
|
struct interface *br_if);
|
2017-09-18 23:45:34 +02:00
|
|
|
static struct interface *zvni_map_to_svi(vlanid_t vid,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct interface *br_if);
|
|
|
|
|
|
|
|
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 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 int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg);
|
|
|
|
static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip);
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_mac_del_all(zebra_vni_t *zvni,
|
2017-07-17 14:03:14 +02:00
|
|
|
int uninstall, int upd_client, u_int32_t flags);
|
|
|
|
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_mac_send_add_to_client(vni_t vni,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_mac_send_del_to_client(vni_t vni,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags);
|
2017-07-17 14:03:14 +02:00
|
|
|
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 int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local);
|
|
|
|
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);
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_lookup(vni_t vni);
|
|
|
|
static zebra_vni_t *zvni_add(vni_t vni);
|
|
|
|
static int zvni_del(zebra_vni_t *zvni);
|
|
|
|
static int zvni_send_add_to_client(zebra_vni_t *zvni);
|
|
|
|
static int zvni_send_del_to_client(vni_t vni);
|
|
|
|
static void zvni_build_hash_table();
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
|
|
|
|
static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip);
|
|
|
|
static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip);
|
|
|
|
static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
|
|
|
|
static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall);
|
|
|
|
static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip);
|
|
|
|
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
|
2017-06-28 10:51:10 +02:00
|
|
|
static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
|
|
|
|
static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
|
|
|
|
static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ethaddr *macaddr, struct ipaddr *ip);
|
|
|
|
static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
|
|
|
|
struct ipaddr *ip);
|
|
|
|
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
|
2017-09-18 23:45:34 +02:00
|
|
|
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
|
2017-06-28 10:51:10 +02:00
|
|
|
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
|
|
|
|
int uninstall);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/* Private functions */
|
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
/*
|
|
|
|
* Return number of valid MACs in a VNI's MAC hash table - all
|
|
|
|
* remote MACs and non-internal (auto) local MACs count.
|
|
|
|
*/
|
|
|
|
static u_int32_t num_valid_macs(zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
u_int32_t num_macs = 0;
|
|
|
|
struct hash *hash;
|
|
|
|
struct hash_backet *hb;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
|
|
|
|
hash = zvni->mac_table;
|
|
|
|
if (!hash)
|
|
|
|
return num_macs;
|
|
|
|
for (i = 0; i < hash->size; i++) {
|
|
|
|
for (hb = hash->index[i]; hb; hb = hb->next) {
|
|
|
|
mac = (zebra_mac_t *)hb->data;
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|
|
|
|
|| !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
|
|
|
|
num_macs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_macs;
|
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (zvrf && zvrf->advertise_gw_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (zvni && zvni->advertise_gw_macip)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Helper function to determine maximum width of neighbor IP address for
|
|
|
|
* display - just because we're dealing with IPv6 addresses that can
|
|
|
|
* widely vary.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
|
|
|
int width;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
n = (zebra_neigh_t *)backet->data;
|
|
|
|
if (!n)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
ipaddr2str(&n->ip, buf, sizeof(buf)), width = strlen(buf);
|
|
|
|
if (width > wctx->addr_width)
|
|
|
|
wctx->addr_width = width;
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a specific neighbor entry.
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2));
|
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
|
|
|
|
vty = (struct vty *)ctxt;
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, "IP: %s\n",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
vty_out(vty, " MAC: %s",
|
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
|
|
|
} else {
|
|
|
|
json_object_string_add(json, "ip", buf2);
|
|
|
|
json_object_string_add(json, "mac", buf1);
|
|
|
|
}
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
2017-07-06 00:03:14 +02:00
|
|
|
if (json == NULL) {
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty, " Remote VTEP: %s",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
2017-07-06 00:03:14 +02:00
|
|
|
} else
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_string_add(json, "remoteVtep",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
|
|
|
}
|
2017-08-19 02:40:52 +02:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, " State: %s",
|
|
|
|
IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active"
|
|
|
|
: "Inactive");
|
|
|
|
}
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, "\n");
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print neighbor hash entry - called for display of all neighbors.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json_vni = NULL, *json_row = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
|
|
|
|
|
|
|
vty = wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_vni = wctx->json;
|
2017-07-17 14:03:14 +02:00
|
|
|
n = (zebra_neigh_t *)backet->data;
|
|
|
|
if (!n)
|
|
|
|
return;
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_vni)
|
|
|
|
json_row = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2));
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
|
|
|
|
&& !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_vni == NULL) {
|
|
|
|
vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width,
|
|
|
|
buf2, "local", buf1);
|
|
|
|
} else {
|
|
|
|
json_object_string_add(json_row, "type", "local");
|
|
|
|
json_object_string_add(json_row, "mac", buf1);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->count++;
|
|
|
|
} else {
|
|
|
|
if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) {
|
|
|
|
if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_vni == NULL) {
|
|
|
|
if (wctx->count == 0)
|
|
|
|
vty_out(vty,
|
|
|
|
"%*s %-6s %-17s %-21s\n",
|
|
|
|
-wctx->addr_width,
|
|
|
|
"Neighbor", "Type",
|
|
|
|
"MAC", "Remote VTEP");
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-17s %-21s\n",
|
2017-06-22 01:37:51 +02:00
|
|
|
-wctx->addr_width, buf2,
|
|
|
|
"remote", buf1,
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
|
|
|
} else {
|
|
|
|
json_object_string_add(json_row, "type",
|
|
|
|
"remote");
|
|
|
|
json_object_string_add(json_row, "mac",
|
|
|
|
buf1);
|
|
|
|
json_object_string_add(
|
|
|
|
json_row, "remoteVtep",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
|
|
|
}
|
|
|
|
wctx->count++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (json_vni == NULL) {
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, "%*s %-6s %-17s %-21s\n",
|
|
|
|
-wctx->addr_width, buf2, "remote", buf1,
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
2017-06-22 01:37:51 +02:00
|
|
|
} else {
|
|
|
|
json_object_string_add(json_row, "type",
|
|
|
|
"remote");
|
|
|
|
json_object_string_add(json_row, "mac", buf1);
|
|
|
|
json_object_string_add(json_row, "remoteVtep",
|
|
|
|
inet_ntoa(n->r_vtep_ip));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
wctx->count++;
|
|
|
|
}
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json_vni)
|
|
|
|
json_object_object_add(json_vni, buf2, json_row);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print neighbors for all VNI.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
|
2017-06-22 01:37:51 +02:00
|
|
|
void **args)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (json_object *)args[1];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty,
|
|
|
|
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_neigh);
|
|
|
|
else {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_object_int_add(json_vni, "numArpNd", num_neigh);
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
}
|
|
|
|
if (!num_neigh) {
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* 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;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_vni;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
|
|
|
|
"Type", "MAC", "Remote VTEP");
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a specific MAC entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf1[20];
|
2017-07-06 00:03:14 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
2017-07-06 00:03:14 +02:00
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, " Remote VTEP: %s",
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
2017-07-06 00:03:14 +02:00
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
|
|
|
|
vty_out(vty, " Auto Mac ");
|
|
|
|
}
|
|
|
|
|
2017-08-09 23:28:39 +02:00
|
|
|
vty_out(vty, "\n");
|
2017-07-06 00:03:14 +02:00
|
|
|
/* 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)),
|
|
|
|
CHECK_FLAG(n->flags, ZEBRA_MAC_LOCAL)
|
|
|
|
? (IS_ZEBRA_NEIGH_ACTIVE(n)
|
|
|
|
? "Active"
|
|
|
|
: "Inactive")
|
|
|
|
: "");
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vty_out(vty, "\n");
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print MAC hash entry - called for display of all MACs.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json_mac_hdr = NULL, *json_mac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf1[20];
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
|
|
|
|
|
|
|
vty = wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_mac_hdr = wctx->json;
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = (zebra_mac_t *)backet->data;
|
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
|
|
|
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json_mac_hdr)
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
|
|
|
|
&& !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) {
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
ifindex_t ifindex;
|
|
|
|
struct interface *ifp;
|
|
|
|
vlanid_t vid;
|
|
|
|
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
ifindex = mac->fwd_info.local.ifindex;
|
|
|
|
ifp = if_lookup_by_index_per_ns(zns, ifindex);
|
|
|
|
if (!ifp) // unexpected
|
|
|
|
return;
|
|
|
|
vid = mac->fwd_info.local.vid;
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s", buf1, "local",
|
|
|
|
ifp->name);
|
|
|
|
else {
|
|
|
|
json_object_string_add(json_mac, "type", "local");
|
|
|
|
json_object_string_add(json_mac, "intf", ifp->name);
|
|
|
|
}
|
|
|
|
if (vid) {
|
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, " %-5u", vid);
|
|
|
|
else
|
|
|
|
json_object_int_add(json_mac, "vlan", vid);
|
|
|
|
}
|
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
else
|
|
|
|
json_object_object_add(json_mac_hdr, buf1, json_mac);
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->count++;
|
2017-07-06 00:03:14 +02:00
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) {
|
|
|
|
if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
|
|
|
|
&wctx->r_vtep_ip)) {
|
|
|
|
if (wctx->count == 0) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_mac_hdr == NULL) {
|
|
|
|
vty_out(vty, "\nVNI %u\n\n",
|
|
|
|
wctx->zvni->vni);
|
|
|
|
vty_out(vty,
|
|
|
|
"%-17s %-6s %-21s %-5s\n",
|
|
|
|
"MAC", "Type",
|
|
|
|
"Intf/Remote VTEP",
|
|
|
|
"VLAN");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s\n", buf1,
|
|
|
|
"remote",
|
|
|
|
inet_ntoa(mac->fwd_info
|
|
|
|
.r_vtep_ip));
|
|
|
|
else {
|
|
|
|
json_object_string_add(json_mac, "type",
|
|
|
|
"remote");
|
|
|
|
json_object_string_add(
|
|
|
|
json_mac, "remoteVtep",
|
|
|
|
inet_ntoa(mac->fwd_info
|
|
|
|
.r_vtep_ip));
|
|
|
|
json_object_object_add(json_mac_hdr,
|
|
|
|
buf1, json_mac);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
wctx->count++;
|
|
|
|
}
|
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json_mac_hdr == NULL)
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s\n", buf1,
|
|
|
|
"remote",
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
|
|
|
else {
|
|
|
|
json_object_string_add(json_mac, "type",
|
|
|
|
"remote");
|
|
|
|
json_object_string_add(
|
|
|
|
json_mac, "remoteVtep",
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip));
|
|
|
|
json_object_object_add(json_mac_hdr, buf1,
|
|
|
|
json_mac);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->count++;
|
|
|
|
}
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print MACs for all VNI.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL, *json_vni = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_macs;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2017-06-22 01:37:51 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vty = (struct vty *)wctx->vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
json = (struct json_object *)wctx->json;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
wctx->zvni = zvni;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/*We are iterating over a new VNI, set the count to 0*/
|
|
|
|
wctx->count = 0;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json) {
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
|
|
|
|
zvni->vni, num_macs);
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
|
|
|
|
"Intf/Remote VTEP", "VLAN");
|
|
|
|
} else
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
}
|
|
|
|
/* 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;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx->json = json;
|
|
|
|
if (json) {
|
|
|
|
if (wctx->count)
|
|
|
|
json_object_object_add(json_vni, "macs", json_mac);
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a specific VNI entry.
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print(zebra_vni_t *zvni, void **ctxt)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
|
|
|
zebra_vtep_t *zvtep;
|
|
|
|
u_int32_t num_macs;
|
|
|
|
u_int32_t num_neigh;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vtep_list = NULL;
|
|
|
|
json_object *json_ip_str = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
vty = ctxt[0];
|
|
|
|
json = ctxt[1];
|
|
|
|
|
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, "VNI: %u\n", zvni->vni);
|
|
|
|
else
|
|
|
|
json_object_int_add(json, "vni", zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (!zvni->vxlan_if) { // unexpected
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " VxLAN interface: unknown\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-06-22 01:37:51 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
|
|
|
|
zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
|
|
|
|
inet_ntoa(zvni->local_vtep_ip));
|
|
|
|
else {
|
|
|
|
json_object_string_add(json, "vxlanInterface",
|
|
|
|
zvni->vxlan_if->name);
|
|
|
|
json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
|
|
|
|
json_object_string_add(json, "vtepIp",
|
|
|
|
inet_ntoa(zvni->local_vtep_ip));
|
2017-07-07 01:33:50 +02:00
|
|
|
json_object_string_add(json, "advertiseGatewayMacip",
|
|
|
|
zvni->advertise_gw_macip ? "Yes" : "No");
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vteps) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " No remote VTEPs known for this VNI\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " Remote VTEPs for this VNI:\n");
|
|
|
|
else
|
|
|
|
json_vtep_list = json_object_new_array();
|
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, " %s\n",
|
|
|
|
inet_ntoa(zvtep->vtep_ip));
|
|
|
|
else {
|
|
|
|
json_ip_str = json_object_new_string(
|
|
|
|
inet_ntoa(zvtep->vtep_ip));
|
|
|
|
json_object_array_add(json_vtep_list,
|
|
|
|
json_ip_str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(json, "numRemoteVteps",
|
|
|
|
json_vtep_list);
|
|
|
|
}
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty,
|
|
|
|
" Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
|
|
|
vty_out(vty,
|
|
|
|
" Number of ARPs (IPv4 and IPv6, local and remote) "
|
|
|
|
"known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
2017-07-07 01:33:50 +02:00
|
|
|
vty_out(vty, " Advertise-gw-macip: %s\n",
|
|
|
|
zvni->advertise_gw_macip ? "Yes" : "No");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print a VNI hash entry - called for display of all VNIs.
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
static void zvni_print_hash(struct hash_backet *backet, void *ctxt[])
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct vty *vty;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
|
|
|
u_int32_t num_vteps = 0;
|
|
|
|
u_int32_t num_macs = 0;
|
|
|
|
u_int32_t num_neigh = 0;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_vni = NULL;
|
|
|
|
json_object *json_ip_str = NULL;
|
|
|
|
json_object *json_vtep_list = NULL;
|
|
|
|
|
|
|
|
vty = ctxt[0];
|
|
|
|
json = ctxt[1];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
|
|
|
if (!zvni)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep = zvni->vteps;
|
|
|
|
while (zvtep) {
|
|
|
|
num_vteps++;
|
|
|
|
zvtep = zvtep->next;
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni,
|
|
|
|
zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
|
|
|
|
inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
|
|
|
|
num_vteps);
|
|
|
|
else {
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
|
|
|
|
json_vni = json_object_new_object();
|
|
|
|
json_object_string_add(json_vni, "vxlanIf",
|
|
|
|
zvni->vxlan_if ? zvni->vxlan_if->name
|
|
|
|
: "unknown");
|
|
|
|
json_object_string_add(json_vni, "vtepIp",
|
|
|
|
inet_ntoa(zvni->local_vtep_ip));
|
|
|
|
json_object_int_add(json_vni, "numMacs", num_macs);
|
|
|
|
json_object_int_add(json_vni, "numArpNd", num_neigh);
|
|
|
|
json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
|
|
|
|
if (num_vteps) {
|
|
|
|
json_vtep_list = json_object_new_array();
|
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
json_ip_str = json_object_new_string(
|
|
|
|
inet_ntoa(zvtep->vtep_ip));
|
|
|
|
json_object_array_add(json_vtep_list,
|
|
|
|
json_ip_str);
|
|
|
|
}
|
|
|
|
json_object_object_add(json_vni, "remoteVteps",
|
|
|
|
json_vtep_list);
|
|
|
|
}
|
|
|
|
json_object_object_add(json, vni_str, json_vni);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Inform BGP about local MACIP.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_macip_send_msg_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ethaddr *macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ipaddr *ip, u_char flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
u_int16_t cmd)
|
|
|
|
{
|
|
|
|
struct zserv *client;
|
|
|
|
struct stream *s;
|
|
|
|
int ipa_len;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
2017-11-27 15:25:32 +01:00
|
|
|
client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s = client->obuf;
|
|
|
|
stream_reset(s);
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zserv_create_header(s, cmd, VRF_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, vni);
|
2017-08-03 14:43:56 +02:00
|
|
|
stream_put(s, macaddr->octet, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ip) {
|
|
|
|
ipa_len = 0;
|
|
|
|
if (IS_IPADDR_V4(ip))
|
|
|
|
ipa_len = IPV4_MAX_BYTELEN;
|
|
|
|
else if (IS_IPADDR_V6(ip))
|
|
|
|
ipa_len = IPV6_MAX_BYTELEN;
|
|
|
|
|
|
|
|
stream_putl(s, ipa_len); /* IP address length */
|
|
|
|
if (ipa_len)
|
|
|
|
stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
|
|
|
|
} else
|
|
|
|
stream_putl(s, 0); /* Just MAC. */
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
stream_putc(s, flags); /* sticky mac/gateway mac */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-06-28 10:51:10 +02:00
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s",
|
|
|
|
(cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
|
2017-06-28 10:51:10 +02:00
|
|
|
flags, prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), vni,
|
|
|
|
zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
if (cmd == ZEBRA_MACIP_ADD)
|
|
|
|
client->macipadd_cnt++;
|
|
|
|
else
|
|
|
|
client->macipdel_cnt++;
|
|
|
|
|
|
|
|
return zebra_server_send_message(client);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make hash key for neighbors.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static unsigned int neigh_hash_keymake(void *p)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n = p;
|
|
|
|
struct ipaddr *ip = &n->ip;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_IPADDR_V4(ip))
|
|
|
|
return jhash_1word(ip->ipaddr_v4.s_addr, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return jhash2(ip->ipaddr_v6.s6_addr32,
|
|
|
|
ZEBRA_NUM_OF(ip->ipaddr_v6.s6_addr32), 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Compare two neighbor hash structures.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int neigh_cmp(const void *p1, const void *p2)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_neigh_t *n1 = p1;
|
|
|
|
const zebra_neigh_t *n2 = p2;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (n1 == NULL && n2 == NULL)
|
|
|
|
return 1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (n1 == NULL || n2 == NULL)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Callback to allocate neighbor hash entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_neigh_alloc(void *p)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_neigh_t *tmp_n = p;
|
|
|
|
zebra_neigh_t *n;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
|
|
|
|
*n = *tmp_n;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return ((void *)n);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Add neighbor entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-06 00:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
|
|
|
|
struct ethaddr *mac)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t tmp_n;
|
|
|
|
zebra_neigh_t *n = NULL;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_n, 0, sizeof(zebra_neigh_t));
|
|
|
|
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
|
|
|
|
assert(n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
memcpy(&n->emac, mac, ETH_ALEN);
|
|
|
|
n->state = ZEBRA_NEIGH_INACTIVE;
|
|
|
|
|
|
|
|
/* Associate the neigh to mac */
|
|
|
|
zmac = zvni_mac_lookup(zvni, mac);
|
|
|
|
if (zmac)
|
|
|
|
listnode_add_sort(zmac->neigh_list, n);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return n;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Delete neighbor entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *tmp_n;
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac = NULL;
|
|
|
|
|
|
|
|
zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (zmac)
|
|
|
|
listnode_delete(zmac->neigh_list, n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_n = hash_release(zvni->neigh_table, n);
|
|
|
|
if (tmp_n)
|
|
|
|
XFREE(MTYPE_NEIGH, tmp_n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Free neighbor hash entry (callback)
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx *wctx = arg;
|
|
|
|
zebra_neigh_t *n = backet->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_NEIGH)
|
|
|
|
&& (n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP)
|
|
|
|
&& (n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
&& IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
|
|
|
|
if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
|
2017-06-28 10:51:10 +02:00
|
|
|
&n->emac, 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (wctx->uninstall)
|
|
|
|
zvni_neigh_uninstall(wctx->zvni, n);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni_neigh_del(wctx->zvni, n);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Delete all neighbor entries from specific VTEP for a particular VNI.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->neigh_table)
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.flags = DEL_REMOTE_NEIGH_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = *r_vtep_ip;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table,
|
|
|
|
(void (*)(struct hash_backet *,
|
|
|
|
void *))zvni_neigh_del_hash_entry,
|
|
|
|
&wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Delete all neighbor entries for this VNI.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_neigh_del_all(zebra_vni_t *zvni,
|
2017-07-17 14:03:14 +02:00
|
|
|
int uninstall, int upd_client, u_int32_t flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->neigh_table)
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.upd_client = upd_client;
|
|
|
|
wctx.flags = flags;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table,
|
|
|
|
(void (*)(struct hash_backet *,
|
|
|
|
void *))zvni_neigh_del_hash_entry,
|
|
|
|
&wctx);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Look up neighbor hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t tmp;
|
|
|
|
zebra_neigh_t *n;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
|
|
|
|
n = hash_lookup(zvni->neigh_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return n;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* Process all neigh associated to a mac upon local mac add event */
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
/* MAC is learnt locally, program all inactive neigh
|
|
|
|
* pointing to this mac */
|
|
|
|
if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"neigh %s (MAC %s) on VNI %u is now ACTIVE",
|
2017-07-06 00:03:14 +02:00
|
|
|
ipaddr2str(&n->ip, buf2,
|
|
|
|
sizeof(buf2)),
|
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
|
|
|
zvni_neigh_send_add_to_client(
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni->vni, &n->ip, &n->emac, 0);
|
2017-07-06 00:03:14 +02:00
|
|
|
} else {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"neigh %s (MAC %s) on VNI %u should NOT be ACTIVE",
|
2017-07-06 00:03:14 +02:00
|
|
|
ipaddr2str(&n->ip, buf2,
|
|
|
|
sizeof(buf2)),
|
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
}
|
|
|
|
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
/* TODO: assume the neigh has moved too ?? */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process all neigh associated to a mac upon local mac del event */
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"neigh %s (MAC %s) on VNI %u is now INACTIVE",
|
2017-07-06 00:03:14 +02:00
|
|
|
ipaddr2str(&n->ip, buf2,
|
|
|
|
sizeof(buf2)),
|
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
|
|
|
zvni_neigh_send_del_to_client(
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni->vni, &n->ip, &n->emac, 0);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
} else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"local MAC %s getting deleted on VNI %u has remote neigh %s",
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni,
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process all neigh associated to a mac entry upon remote mac add */
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"neigh %s (MAC %s) on VNI %u INACTIVE",
|
2017-07-06 00:03:14 +02:00
|
|
|
ipaddr2str(&n->ip, buf2,
|
|
|
|
sizeof(buf2)),
|
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(n);
|
|
|
|
zvni_neigh_send_del_to_client(
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni->vni, &n->ip, &n->emac, 0);
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process all neigh associated to mac entry upon remote mac del */
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
zebra_mac_t *zmac)
|
|
|
|
{
|
|
|
|
zebra_neigh_t *n = NULL;
|
|
|
|
struct listnode *node = NULL;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"remote MAC %s getting deleted on VNI %u has local neigh %s",
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
zvni->vni,
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about local neighbor addition.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_neigh_send_add_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ipaddr *ip,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
ZEBRA_MACIP_ADD);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about local neighbor deletion.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_neigh_send_del_to_client(vni_t vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct ipaddr *ip,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
ZEBRA_MACIP_DEL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install remote neighbor into the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return -1;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_add_neigh(vlan_if, &n->ip, &n->emac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Uninstall remote neighbor from the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_del_neigh(vlan_if, &n->ip);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Install neighbor hash entry - called upon access VLAN change.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_neigh_t *n;
|
|
|
|
struct neigh_walk_ctx *wctx = ctxt;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
n = (zebra_neigh_t *)backet->data;
|
|
|
|
if (!n)
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
|
|
|
|
zvni_neigh_install(wctx->zvni, n);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Get the VRR interface for SVI if any */
|
|
|
|
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(ifp->vrf_id);
|
|
|
|
assert(zvrf);
|
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) {
|
2017-06-28 10:51:10 +02:00
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (zif->link == ifp)
|
|
|
|
return tmp_if;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct listnode *cnode = NULL, *cnnode = NULL;
|
|
|
|
struct connected *c = NULL;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
|
|
|
|
struct ipaddr ip;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->address->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (c->address->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_gw_macip_del(ifp, zvni, &ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
|
|
|
|
{
|
|
|
|
struct listnode *cnode = NULL, *cnnode = NULL;
|
|
|
|
struct connected *c = NULL;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
|
|
|
|
struct ipaddr ip;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->address->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (c->address->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* zvni_gw_macip_add_to_client
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
mac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!mac) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_err("Failed to add MAC %s intf %s(%u) VID %u",
|
2017-06-28 10:51:10 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vxl->access_vlan);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vxl->access_vlan;
|
|
|
|
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n) {
|
2017-07-06 00:03:14 +02:00
|
|
|
n = zvni_neigh_add(zvni, ip, macaddr);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!n) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-08-25 02:43:29 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
2017-06-28 10:51:10 +02:00
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2017-08-25 14:07:58 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
2017-06-28 10:51:10 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)));
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
ZEBRA_MAC_TYPE_GW);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* zvni_gw_macip_del_from_client
|
|
|
|
*/
|
|
|
|
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;
|
2017-08-25 02:43:29 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-06-28 10:51:10 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
/* If the neigh entry is not present nothing to do*/
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* mac entry should be present */
|
|
|
|
mac = zvni_mac_lookup(zvni, &n->emac);
|
2017-08-25 02:43:29 +02:00
|
|
|
if (!mac) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_err("MAC %s doesnt exists for neigh %s on VNI %u",
|
2017-08-25 02:43:29 +02:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
|
2017-06-28 10:51:10 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
|
2017-08-25 02:43:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* If the entry is not local nothing to do*/
|
|
|
|
if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2017-08-25 02:43:29 +02:00
|
|
|
prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
|
2017-06-28 10:51:10 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)));
|
|
|
|
|
|
|
|
/* Remove neighbor from BGP. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
|
2017-06-28 10:51:10 +02:00
|
|
|
ZEBRA_MAC_TYPE_GW);
|
|
|
|
|
|
|
|
/* Delete this neighbor entry. */
|
|
|
|
zvni_neigh_del(zvni, n);
|
|
|
|
|
|
|
|
/* see if the mac needs to be deleted as well*/
|
2017-08-25 14:07:58 +02:00
|
|
|
if (mac)
|
|
|
|
zvni_deref_ip2mac(zvni, mac, 0);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet,
|
2017-09-18 23:45:34 +02:00
|
|
|
void *ctxt)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* Add primary SVI MAC*/
|
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
return;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Del primary MAC-IP */
|
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Del VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_del_macip_for_intf(vrr_if, zvni);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
|
2017-09-18 23:45:34 +02:00
|
|
|
void *ctxt)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
|
|
|
if (!zvni)
|
|
|
|
return;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!advertise_gw_macip_enabled(zvni))
|
2017-06-28 10:51:10 +02:00
|
|
|
return;
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
|
2017-06-28 10:51:10 +02:00
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Add primary SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Make hash key for MAC.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static unsigned int mac_hash_keymake(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *pmac = p;
|
2017-08-03 13:43:47 +02:00
|
|
|
const void *pnt = (void *)pmac->macaddr.octet;
|
|
|
|
|
2017-08-03 14:43:56 +02:00
|
|
|
return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Compare two MAC addresses.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int mac_cmp(const void *p1, const void *p2)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_mac_t *pmac1 = p1;
|
|
|
|
const zebra_mac_t *pmac2 = p2;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (pmac1 == NULL && pmac2 == NULL)
|
|
|
|
return 1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (pmac1 == NULL || pmac2 == NULL)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet,
|
2017-08-03 14:43:56 +02:00
|
|
|
ETH_ALEN)
|
2017-07-17 14:03:14 +02:00
|
|
|
== 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate MAC hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_mac_alloc(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_mac_t *tmp_mac = p;
|
|
|
|
zebra_mac_t *mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
|
|
|
|
*mac = *tmp_mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return ((void *)mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add MAC entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t tmp_mac;
|
|
|
|
zebra_mac_t *mac = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_mac, 0, sizeof(zebra_mac_t));
|
2017-08-03 14:43:56 +02:00
|
|
|
memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
|
|
|
|
assert(mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
mac->neigh_list = list_new();
|
|
|
|
mac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete MAC entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *tmp_mac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-05 16:51:01 +02:00
|
|
|
list_delete_and_null(&mac->neigh_list);
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_mac = hash_release(zvni->mac_table, mac);
|
|
|
|
if (tmp_mac)
|
|
|
|
XFREE(MTYPE_MAC, tmp_mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free MAC hash entry (callback)
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx *wctx = arg;
|
|
|
|
zebra_mac_t *mac = backet->data;
|
|
|
|
u_char sticky = 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_MAC)
|
|
|
|
&& (mac->flags & ZEBRA_MAC_REMOTE))
|
|
|
|
|| ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
|
|
|
|
&& (mac->flags & ZEBRA_MAC_REMOTE)
|
|
|
|
&& IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
|
|
|
|
&wctx->r_vtep_ip))) {
|
|
|
|
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
|
|
|
|
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1
|
|
|
|
: 0;
|
2017-06-28 10:51:10 +02:00
|
|
|
zvni_mac_send_del_to_client(
|
2017-09-18 23:45:34 +02:00
|
|
|
wctx->zvni->vni, &mac->macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (wctx->uninstall)
|
|
|
|
zvni_mac_uninstall(wctx->zvni, mac, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni_mac_del(wctx->zvni, mac);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all MAC entries from specific VTEP for a particular VNI.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall,
|
|
|
|
struct in_addr *r_vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->mac_table)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.flags = DEL_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = *r_vtep_ip;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-22 14:52:33 +02:00
|
|
|
hash_iterate(zvni->mac_table, (void (*)(struct hash_backet *,
|
|
|
|
void *))zvni_mac_del_hash_entry,
|
|
|
|
&wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all MAC entries for this VNI.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_mac_del_all(zebra_vni_t *zvni,
|
2017-07-17 14:03:14 +02:00
|
|
|
int uninstall, int upd_client, u_int32_t flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->mac_table)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.uninstall = uninstall;
|
|
|
|
wctx.upd_client = upd_client;
|
|
|
|
wctx.flags = flags;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-22 14:52:33 +02:00
|
|
|
hash_iterate(zvni->mac_table, (void (*)(struct hash_backet *,
|
|
|
|
void *))zvni_mac_del_hash_entry,
|
|
|
|
&wctx);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up MAC hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t tmp;
|
|
|
|
zebra_mac_t *pmac;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2017-08-03 14:43:56 +02:00
|
|
|
memcpy(&tmp.macaddr, mac, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
pmac = hash_lookup(zvni->mac_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return pmac;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local MAC addition.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_mac_send_add_to_client(vni_t vni,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
ZEBRA_MACIP_ADD);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local MAC deletion.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_mac_send_del_to_client(vni_t vni,
|
2017-06-28 10:51:10 +02:00
|
|
|
struct ethaddr *macaddr, u_char flags)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
|
2017-07-17 14:03:14 +02:00
|
|
|
ZEBRA_MACIP_DEL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC
|
2017-09-18 23:45:34 +02:00
|
|
|
* notifications, to see if they are of interest.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
|
|
|
|
struct interface *br_if, vlanid_t vid)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
u_char bridge_vlan_aware;
|
|
|
|
zebra_vni_t *zvni;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
|
|
|
/* TODO: Optimize with a hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
if (!if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zif->brslave_info.br_if != br_if)
|
|
|
|
continue;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!found)
|
2017-07-17 14:03:14 +02:00
|
|
|
return NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vxl->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map SVI and associated bridge to a VNI. This is invoked upon getting
|
|
|
|
* neighbor notifications, to see if they are of interest.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if)
|
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
u_char bridge_vlan_aware;
|
|
|
|
vlanid_t vid = 0;
|
|
|
|
zebra_vni_t *zvni;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-20 02:28:58 +02:00
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* 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. */
|
2017-09-18 23:45:34 +02:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
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;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!found)
|
2017-07-17 14:03:14 +02:00
|
|
|
return NULL;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vxl->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
|
|
|
|
* of two cases:
|
|
|
|
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
|
|
|
|
* linked to the bridge
|
|
|
|
* (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface
|
|
|
|
* itself
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *tmp_if = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_bridge *br;
|
|
|
|
struct zebra_l2info_vlan *vl;
|
|
|
|
u_char bridge_vlan_aware;
|
2017-09-18 23:45:34 +02:00
|
|
|
int found = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
/* Defensive check, caller expected to invoke only with valid bridge. */
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
|
|
|
br = &zif->l2info.br;
|
|
|
|
bridge_vlan_aware = br->vlan_aware;
|
|
|
|
|
|
|
|
/* Check oper status of the SVI. */
|
|
|
|
if (!bridge_vlan_aware)
|
|
|
|
return if_is_operative(br_if) ? br_if : NULL;
|
|
|
|
|
|
|
|
/* Identify corresponding VLAN interface. */
|
|
|
|
/* TODO: Optimize with a hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Check oper status of the SVI. */
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!tmp_if || !if_is_operative(tmp_if))
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|
|
|
|
|| zif->link != br_if)
|
|
|
|
continue;
|
|
|
|
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (vl->vid == vid) {
|
|
|
|
found = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
return found ? tmp_if : NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install remote MAC into the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
u_char sticky;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!(mac->flags & ZEBRA_MAC_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
|
2017-05-15 23:42:57 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr,
|
|
|
|
mac->fwd_info.r_vtep_ip, sticky);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall remote MAC from the kernel. In the scenario where the MAC
|
|
|
|
* moves to remote, we have to uninstall any existing local entry first.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct in_addr vtep_ip = {.s_addr = 0};
|
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct interface *ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!local && !(mac->flags & ZEBRA_MAC_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = zvni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (local) {
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
ifp = if_lookup_by_index_per_ns(zns,
|
|
|
|
mac->fwd_info.local.ifindex);
|
|
|
|
if (!ifp) // unexpected
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
vtep_ip = mac->fwd_info.r_vtep_ip;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip,
|
|
|
|
local);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install MAC hash entry - called upon access VLAN change.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_mac_t *mac;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
mac = (zebra_mac_t *)backet->data;
|
|
|
|
if (!mac)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
zvni_mac_install(wctx->zvni, mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decrement neighbor refcount of MAC; uninstall and free it if
|
|
|
|
* appropriate.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
|
|
|
|
int uninstall)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-08-30 17:23:01 +02:00
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)
|
|
|
|
|| !list_isempty(mac->neigh_list))
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (uninstall)
|
|
|
|
zvni_mac_uninstall(zvni, mac, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_mac_del(zvni, mac);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read and populate local MACs and neighbors corresponding to this VNI.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_read_mac_neigh(zebra_vni_t *zvni,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct interface *ifp)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct interface *vlan_if;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
2017-06-28 10:51:10 +02:00
|
|
|
struct interface *vrr_if;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zif->brslave_info.bridge_ifindex);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
|
|
|
|
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (vlan_if) {
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni)) {
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
neigh_read_for_vlan(zns, vlan_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Hash function for VNI.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static unsigned int vni_hash_keymake(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *zvni = p;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (jhash_1word(zvni->vni, 0));
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare 2 VNI hash entries.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int vni_hash_cmp(const void *p1, const void *p2)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *zvni1 = p1;
|
|
|
|
const zebra_vni_t *zvni2 = p2;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return (zvni1->vni == zvni2->vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate VNI hash entry.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void *zvni_alloc(void *p)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
const zebra_vni_t *tmp_vni = p;
|
|
|
|
zebra_vni_t *zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = XCALLOC(MTYPE_ZVNI, sizeof(zebra_vni_t));
|
|
|
|
zvni->vni = tmp_vni->vni;
|
|
|
|
return ((void *)zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_lookup(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t tmp_vni;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
assert(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_vni, 0, sizeof(zebra_vni_t));
|
|
|
|
tmp_vni.vni = vni;
|
|
|
|
zvni = hash_lookup(zvrf->vni_table, &tmp_vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static zebra_vni_t *zvni_add(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t tmp_zvni;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
assert(zvrf);
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&tmp_zvni, 0, sizeof(zebra_vni_t));
|
|
|
|
tmp_zvni.vni = vni;
|
|
|
|
zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc);
|
|
|
|
assert(zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create hash table for MAC */
|
|
|
|
zvni->mac_table =
|
|
|
|
hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table");
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create hash table for neighbors */
|
|
|
|
zvni->neigh_table = hash_create(neigh_hash_keymake, neigh_cmp,
|
|
|
|
"Zebra VNI Neighbor Table");
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete VNI hash entry.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_del(zebra_vni_t *zvni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *tmp_zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
assert(zvrf);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni->vxlan_if = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the neighbor hash table. */
|
|
|
|
hash_free(zvni->neigh_table);
|
|
|
|
zvni->neigh_table = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the MAC hash table. */
|
|
|
|
hash_free(zvni->mac_table);
|
|
|
|
zvni->mac_table = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
|
|
|
tmp_zvni = hash_release(zvrf->vni_table, zvni);
|
|
|
|
if (tmp_zvni)
|
|
|
|
XFREE(MTYPE_ZVNI, tmp_zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local VNI addition.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_send_add_to_client(zebra_vni_t *zvni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zserv *client;
|
|
|
|
struct stream *s;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-11-27 15:25:32 +01:00
|
|
|
client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
s = client->obuf;
|
|
|
|
stream_reset(s);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, zvni->vni);
|
|
|
|
stream_put_in_addr(s, &zvni->local_vtep_ip);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Send VNI_ADD %u %s to %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni->vni, inet_ntoa(zvni->local_vtep_ip),
|
|
|
|
zebra_route_string(client->proto));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
client->vniadd_cnt++;
|
|
|
|
return zebra_server_send_message(client);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local VNI deletion.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static int zvni_send_del_to_client(vni_t vni)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zserv *client;
|
|
|
|
struct stream *s;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-11-27 15:25:32 +01:00
|
|
|
client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
s = client->obuf;
|
|
|
|
stream_reset(s);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zserv_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
stream_putl(s, vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Send VNI_DEL %u to %s", vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
client->vnidel_cnt++;
|
|
|
|
return zebra_server_send_message(client);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the VNI hash table by going over the VxLAN interfaces. This
|
|
|
|
* is called when EVPN (advertise-all-vni) is enabled.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
static void zvni_build_hash_table()
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
2017-07-17 14:03:14 +02:00
|
|
|
struct interface *ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Walk VxLAN interfaces and create VNI hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
vni_t vni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
vxl = &zif->l2info.vxl;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
vni = vxl->vni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Create VNI hash for intf %s(%u) VNI %u local IP %s",
|
|
|
|
ifp->name, ifp->ifindex, vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
inet_ntoa(vxl->vtep_ip));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* VNI hash entry is not expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"VNI hash already present for IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_add(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add VNI hash, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->vxlan_if = ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Inform BGP if interface is up and mapped to bridge. */
|
|
|
|
if (if_is_operative(ifp) && zif->brslave_info.br_if)
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if remote VTEP matches with prefix.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip));
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate remote VTEP in VNI hash table.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
|
|
|
|
if (zvni_vtep_match(vtep_ip, zvtep))
|
|
|
|
break;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add remote VTEP to VNI hash table.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
|
|
|
|
if (!zvtep) {
|
|
|
|
zlog_err("Failed to alloc VTEP entry, VNI %u", zvni->vni);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep->vtep_ip = *vtep_ip;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvni->vteps)
|
|
|
|
zvni->vteps->prev = zvtep;
|
|
|
|
zvtep->next = zvni->vteps;
|
|
|
|
zvni->vteps = zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return zvtep;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove remote VTEP from VNI hash table.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvtep->next)
|
|
|
|
zvtep->next->prev = zvtep->prev;
|
|
|
|
if (zvtep->prev)
|
|
|
|
zvtep->prev->next = zvtep->next;
|
|
|
|
else
|
|
|
|
zvni->vteps = zvtep->next;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvtep->prev = zvtep->next = NULL;
|
|
|
|
XFREE(MTYPE_ZVNI_VTEP, zvtep);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all remote VTEPs for this VNI (upon VNI delete). Also
|
|
|
|
* uninstall from kernel if asked to.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vtep_t *zvtep, *zvtep_next;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return -1;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next) {
|
|
|
|
zvtep_next = zvtep->next;
|
|
|
|
if (uninstall)
|
|
|
|
zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
|
|
|
|
zvni_vtep_del(zvni, zvtep);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install remote VTEP into the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall remote VTEP from the kernel.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return kernel_del_vtep(zvni->vni, zvni->vxlan_if, vtep_ip);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cleanup VNI/VTEP and update kernel
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = (zebra_vni_t *)backet->data;
|
|
|
|
if (!zvni)
|
|
|
|
return;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all neighbors and MACs, if any. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 1);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Delete the hash entry. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_del(zvni);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Public functions */
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display Neighbors for a VNI (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, u_char use_json)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* 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;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display neighbors across all VNIs (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display specific neighbor for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf, vni_t vni,
|
2017-06-22 01:37:51 +02:00
|
|
|
struct ipaddr *ip, u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_neigh_t *n;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!use_json)
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested neighbor does not exist in VNI %u\n",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
zvni_print_neigh(n, vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display neighbors for a VNI from specific VTEP (VTY command handler).
|
|
|
|
* By definition, these are remote neighbors.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, struct in_addr vtep_ip,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_neigh = hashcount(zvni->neigh_table);
|
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display MACs for a VNI (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_macs;
|
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_mac;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
|
|
|
vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type",
|
|
|
|
"Intf/Remote VTEP", "VLAN");
|
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display MACs for all VNIs (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display MACs for all VNIs (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
struct in_addr vtep_ip,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display specific MAC for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni, struct ethaddr *macaddr)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
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);
|
|
|
|
return;
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_print_mac(mac, vty);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display MACs for a VNI from specific VTEP (VTY command handler).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
|
2017-06-22 01:37:51 +02:00
|
|
|
vni_t vni, struct in_addr vtep_ip,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
u_int32_t num_macs;
|
|
|
|
struct mac_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-10-05 07:30:53 +02:00
|
|
|
num_macs = num_valid_macs(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
|
|
|
|
wctx.zvni = zvni;
|
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json_mac;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_int_add(json, "numMacs", wctx.count);
|
|
|
|
if (wctx.count)
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI information (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
zvni_print(zvni, (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);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI hash table (VTY command handler).
|
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
u_char use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
u_int32_t num_vnis;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
num_vnis = hashcount(zvrf->vni_table);
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!num_vnis) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
2017-07-07 01:33:50 +02:00
|
|
|
json_object_string_add(json, "advertiseGatewayMacip",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object_int_add(json, "numVnis", num_vnis);
|
|
|
|
} else {
|
2017-07-07 01:33:50 +02:00
|
|
|
vty_out(vty, "Advertise gateway mac-ip: %s\n",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty, "Number of VNIs: %u\n", num_vnis);
|
|
|
|
vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI",
|
|
|
|
"VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
|
|
|
|
"# Remote VTEPs");
|
|
|
|
}
|
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vni_table,
|
|
|
|
(void (*)(struct hash_backet *, void *))zvni_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);
|
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Handle neighbor delete (on a VLAN device / L3 interface) from the
|
|
|
|
* kernel. This may result in either the neighbor getting deleted from
|
|
|
|
* our database or being re-added to the kernel (if it is a valid
|
|
|
|
* remote neighbor).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_neigh_del(struct interface *ifp,
|
|
|
|
struct interface *link_if, struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
2017-07-06 00:03:14 +02:00
|
|
|
char buf2[ETHER_ADDR_STRLEN];
|
|
|
|
zebra_mac_t *zmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_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",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Del neighbor %s intf %s(%u) -> VNI %u",
|
|
|
|
ipaddr2str(ip, buf, sizeof(buf)),
|
2017-07-17 14:03:14 +02:00
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
|
|
|
|
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (!zmac) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Trying to del a neigh %s without a mac %s on VNI %u",
|
|
|
|
ipaddr2str(ip, buf, sizeof(buf)),
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If it is a remote entry, the kernel has aged this out or someone has
|
|
|
|
* deleted it, it needs to be re-installed as Quagga is the owner.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
|
|
|
|
zvni_neigh_install(zvni, n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove neighbor from BGP. */
|
2017-07-06 00:03:14 +02:00
|
|
|
if (IS_ZEBRA_NEIGH_ACTIVE(n))
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
|
2017-07-06 00:03:14 +02:00
|
|
|
0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* Delete this neighbor entry. */
|
|
|
|
zvni_neigh_del(zvni, n);
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* see if the AUTO mac needs to be deleted */
|
|
|
|
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
|
2017-08-19 02:40:52 +02:00
|
|
|
&& !listcount(zmac->neigh_list))
|
2017-07-06 00:03:14 +02:00
|
|
|
zvni_mac_del(zvni, zmac);
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-08-18 02:39:20 +02:00
|
|
|
* Handle neighbor add or update (on a VLAN device / L3 interface)
|
|
|
|
* from the kernel.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
|
|
|
|
struct interface *link_if,
|
|
|
|
struct ipaddr *ip,
|
|
|
|
struct ethaddr *macaddr, u_int16_t state,
|
|
|
|
u_char ext_learned)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_neigh_t *n;
|
2017-08-14 06:52:04 +02:00
|
|
|
zebra_mac_t *zmac, *old_zmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_svi(ifp, link_if);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x "
|
2017-07-17 14:03:14 +02:00
|
|
|
"%s-> VNI %u",
|
2017-09-18 23:45:34 +02:00
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, state, ext_learned ? "ext-learned " : "",
|
|
|
|
zvni->vni);
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* create a dummy MAC if the MAC is not already present */
|
|
|
|
zmac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!zmac) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"AUTO MAC %s created for neigh %s on VNI %u",
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
|
|
|
|
|
|
|
|
zmac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!zmac) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_warn("Failed to add MAC %s VNI %u",
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
|
|
|
|
memset(&zmac->flags, 0, sizeof(u_int32_t));
|
|
|
|
SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If same entry already exists, it might be a change or it might be a
|
|
|
|
* move from remote to local.
|
|
|
|
*/
|
|
|
|
n = zvni_neigh_lookup(zvni, ip);
|
|
|
|
if (n) {
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
|
|
|
|
if (memcmp(n->emac.octet, macaddr->octet,
|
2017-08-03 14:43:56 +02:00
|
|
|
ETH_ALEN)
|
2017-07-17 14:03:14 +02:00
|
|
|
== 0) {
|
2017-08-14 06:52:04 +02:00
|
|
|
/* Update any params and return - client doesn't
|
|
|
|
* care about a purely local change.
|
|
|
|
*/
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
return 0;
|
2017-08-19 02:23:30 +02:00
|
|
|
}
|
2017-08-14 06:52:04 +02:00
|
|
|
|
2017-08-19 02:23:30 +02:00
|
|
|
/* 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.
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
|
2017-08-30 17:23:01 +02:00
|
|
|
&n->emac, 0);
|
2017-08-19 02:23:30 +02:00
|
|
|
old_zmac = zvni_mac_lookup(zvni, &n->emac);
|
|
|
|
if (old_zmac) {
|
2017-08-30 17:23:01 +02:00
|
|
|
listnode_delete(old_zmac->neigh_list, n);
|
2017-08-19 02:23:30 +02:00
|
|
|
zvni_deref_ip2mac(zvni, old_zmac, 0);
|
2017-08-14 06:52:04 +02:00
|
|
|
}
|
2017-08-19 02:23:30 +02:00
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->ifindex = ifp->ifindex;
|
|
|
|
memcpy(&n->emac, macaddr, ETH_ALEN);
|
|
|
|
|
|
|
|
/* Link to new MAC */
|
|
|
|
listnode_add_sort(zmac->neigh_list, n);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else if (ext_learned)
|
|
|
|
/* The neighbor is remote and that is the notification we got.
|
2017-07-22 14:52:33 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2017-08-18 02:39:20 +02:00
|
|
|
/* TODO: Evaluate if we need to do anything here. */
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
/* Neighbor has moved from remote to local. */
|
|
|
|
{
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
n->r_vtep_ip.s_addr = 0;
|
2017-08-14 06:52:04 +02:00
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->ifindex = ifp->ifindex;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-07-06 00:03:14 +02:00
|
|
|
n = zvni_neigh_add(zvni, ip, macaddr);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!n) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-08-14 06:52:04 +02:00
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
n->ifindex = ifp->ifindex;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* Before we program this in BGP, we need to check if MAC is locally
|
|
|
|
* learnt as well */
|
|
|
|
if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Skipping neigh %s add to client as MAC %s is not local on VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-07-06 00:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
/* Inform BGP. */
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("neigh %s (MAC %s) is now ACTIVE on VNI %u",
|
|
|
|
ipaddr2str(ip, buf2, sizeof(buf2)),
|
2017-08-30 17:23:01 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
ZEBRA_NEIGH_SET_ACTIVE(n);
|
2017-09-18 23:45:34 +02:00
|
|
|
return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to delete a remote MACIP for a VNI.
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
u_short l = 0, ipa_len;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
s = client->ibuf;
|
|
|
|
|
|
|
|
while (l < length) {
|
|
|
|
/* Obtain each remote MACIP and process. */
|
|
|
|
/* Message contains VNI, followed by MAC followed by IP (if any)
|
|
|
|
* followed by remote VTEP IP.
|
|
|
|
*/
|
|
|
|
mac = NULL;
|
|
|
|
n = NULL;
|
|
|
|
memset(&ip, 0, sizeof(ip));
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
|
|
|
|
STREAM_GETL(s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ipa_len) {
|
|
|
|
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
|
|
|
|
: IPADDR_V6;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&ip.ip.addr, s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-03 14:43:56 +02:00
|
|
|
l += 4 + ETH_ALEN + 4 + ipa_len;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s from %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
|
|
|
|
inet_ntoa(vtep_ip),
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to locate VNI hash upon remote MACIP DEL, "
|
2017-09-18 23:45:34 +02:00
|
|
|
"VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
2017-07-20 18:54:46 +02:00
|
|
|
if (!ifp) {
|
2017-07-17 14:03:14 +02:00
|
|
|
zlog_err(
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote MACIP DEL",
|
|
|
|
vni, zvni);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* The remote VTEP specified is normally expected to exist, but
|
|
|
|
* it is
|
|
|
|
* possible that the peer may delete the VTEP before deleting
|
|
|
|
* any MACs
|
|
|
|
* referring to the VTEP, in which case the handler (see
|
|
|
|
* remote_vtep_del)
|
|
|
|
* would have already deleted the MACs.
|
|
|
|
*/
|
|
|
|
if (!zvni_vtep_find(zvni, &vtep_ip))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mac = zvni_mac_lookup(zvni, &macaddr);
|
|
|
|
if (ipa_len)
|
|
|
|
n = zvni_neigh_lookup(zvni, &ip);
|
|
|
|
|
|
|
|
if (n && !mac) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate MAC %s for neigh %s VNI %u",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf, sizeof(buf)),
|
2017-09-18 23:45:34 +02:00
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the remote mac or neighbor doesn't exist there is nothing
|
|
|
|
* more
|
|
|
|
* to do. Otherwise, uninstall the entry and then remove it.
|
|
|
|
*/
|
|
|
|
if (!mac && !n)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Uninstall remote neighbor or MAC. */
|
|
|
|
if (n) {
|
|
|
|
/* When the MAC changes for an IP, it is possible the
|
|
|
|
* client may
|
|
|
|
* update the new MAC before trying to delete the "old"
|
|
|
|
* neighbor
|
|
|
|
* (as these are two different MACIP routes). Do the
|
|
|
|
* delete only
|
|
|
|
* if the MAC matches.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
|
|
|
|
&& (memcmp(n->emac.octet, macaddr.octet,
|
2017-08-03 14:43:56 +02:00
|
|
|
ETH_ALEN)
|
2017-07-17 14:03:14 +02:00
|
|
|
== 0)) {
|
|
|
|
zvni_neigh_uninstall(zvni, n);
|
|
|
|
zvni_neigh_del(zvni, n);
|
|
|
|
zvni_deref_ip2mac(zvni, mac, 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_process_neigh_on_remote_mac_del(zvni,
|
2017-07-06 00:03:14 +02:00
|
|
|
mac);
|
|
|
|
|
2017-08-09 23:28:39 +02:00
|
|
|
if (list_isempty(mac->neigh_list)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_mac_uninstall(zvni, mac, 0);
|
|
|
|
zvni_mac_del(zvni, mac);
|
|
|
|
} else
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to add a remote MACIP for a VNI. This
|
|
|
|
* could be just the add of a MAC address or the add of a neighbor
|
|
|
|
* (IP+MAC).
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
|
|
|
zebra_mac_t *mac, *old_mac;
|
|
|
|
zebra_neigh_t *n;
|
|
|
|
u_short l = 0, ipa_len;
|
|
|
|
int update_mac = 0, update_neigh = 0;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
|
|
|
u_char sticky;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
|
|
|
zlog_warn("%s: EVPN Not turned on yet we have received a remote_macip add zapi callback",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
s = client->ibuf;
|
|
|
|
|
|
|
|
while (l < length) {
|
|
|
|
/* Obtain each remote MACIP and process. */
|
|
|
|
/* Message contains VNI, followed by MAC followed by IP (if any)
|
|
|
|
* followed by remote VTEP IP.
|
|
|
|
*/
|
|
|
|
update_mac = update_neigh = 0;
|
|
|
|
mac = NULL;
|
|
|
|
n = NULL;
|
|
|
|
memset(&ip, 0, sizeof(ip));
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
STREAM_GET(&macaddr.octet, s, ETH_ALEN);
|
|
|
|
STREAM_GETL(s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (ipa_len) {
|
|
|
|
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
|
|
|
|
: IPADDR_V6;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&ip.ip.addr, s, ipa_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-08-03 14:43:56 +02:00
|
|
|
l += 4 + ETH_ALEN + 4 + ipa_len;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
/* Get 'sticky' flag. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, sticky);
|
2017-07-17 14:03:14 +02:00
|
|
|
l++;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
|
|
|
|
sticky ? "sticky " : "",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf, sizeof(buf)),
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
|
|
|
|
inet_ntoa(vtep_ip),
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash upon remote MACIP ADD, VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp) {
|
2017-07-17 14:03:14 +02:00
|
|
|
zlog_err(
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote MACIP add",
|
|
|
|
vni, zvni);
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* The remote VTEP specified should normally exist, but it is
|
|
|
|
* possible
|
|
|
|
* that when peering comes up, peer may advertise MACIP routes
|
|
|
|
* before
|
|
|
|
* advertising type-3 routes.
|
|
|
|
*/
|
|
|
|
zvtep = zvni_vtep_find(zvni, &vtep_ip);
|
|
|
|
if (!zvtep) {
|
|
|
|
if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add remote VTEP, VNI %u zvni %p",
|
|
|
|
vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_vtep_install(zvni, &vtep_ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First, check if the remote MAC is unknown or has a change. If
|
|
|
|
* so,
|
|
|
|
* that needs to be updated first. Note that client could
|
|
|
|
* install
|
|
|
|
* MAC and MACIP separately or just install the latter.
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
|| !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip))
|
|
|
|
update_mac = 1;
|
|
|
|
|
|
|
|
if (update_mac) {
|
|
|
|
if (!mac) {
|
|
|
|
mac = zvni_mac_add(zvni, &macaddr);
|
|
|
|
if (!mac) {
|
|
|
|
zlog_warn(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add MAC %s VNI %u Remote VTEP %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(&macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
vni, inet_ntoa(vtep_ip));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is this MAC created for a MACIP? */
|
|
|
|
if (ipa_len)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "auto" and "remote" forwarding info. */
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
mac->fwd_info.r_vtep_ip = vtep_ip;
|
|
|
|
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_process_neigh_on_remote_mac_add(zvni, mac);
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Install the entry. */
|
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is no IP, continue - after clearing AUTO flag of
|
|
|
|
* MAC. */
|
|
|
|
if (!ipa_len) {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the remote neighbor itself is unknown or has a
|
|
|
|
* change.
|
|
|
|
* If so, create or update and then install the entry.
|
|
|
|
*/
|
|
|
|
n = zvni_neigh_lookup(zvni, &ip);
|
|
|
|
if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
|
|
|
|
|| (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0)
|
|
|
|
|| !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip))
|
|
|
|
update_neigh = 1;
|
|
|
|
|
|
|
|
if (update_neigh) {
|
|
|
|
if (!n) {
|
2017-07-06 00:03:14 +02:00
|
|
|
n = zvni_neigh_add(zvni, &ip, &macaddr);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!n) {
|
|
|
|
zlog_warn(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
ipaddr2str(&ip, buf1,
|
|
|
|
sizeof(buf1)),
|
|
|
|
prefix_mac2str(&macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
vni, inet_ntoa(vtep_ip));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (memcmp(&n->emac, &macaddr, sizeof(macaddr))
|
|
|
|
!= 0) {
|
2017-08-09 23:28:39 +02:00
|
|
|
/* MAC change, update neigh list for old and new
|
|
|
|
* mac */
|
2017-07-17 14:03:14 +02:00
|
|
|
old_mac = zvni_mac_lookup(zvni, &n->emac);
|
2017-08-09 23:28:39 +02:00
|
|
|
if (old_mac) {
|
|
|
|
listnode_delete(old_mac->neigh_list, n);
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_deref_ip2mac(zvni, old_mac, 1);
|
2017-08-09 23:28:39 +02:00
|
|
|
}
|
|
|
|
listnode_add_sort(mac->neigh_list, n);
|
2017-07-06 00:03:14 +02:00
|
|
|
memcpy(&n->emac, &macaddr, ETH_ALEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "remote" forwarding info. */
|
|
|
|
UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
|
|
|
|
/* TODO: Handle MAC change. */
|
|
|
|
n->r_vtep_ip = vtep_ip;
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
|
|
|
|
/* Install the entry. */
|
|
|
|
zvni_neigh_install(zvni, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle notification of MAC add/update over VxLAN. If the kernel is notifying
|
|
|
|
* us, this must involve a multihoming scenario. Treat this as implicit delete
|
|
|
|
* of any prior local MAC.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_check_del_local_mac(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
u_char sticky;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a local entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add/update remote MAC %s intf %s(%u) VNI %u - del local",
|
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
2017-07-17 14:03:14 +02:00
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Remove MAC from BGP. */
|
|
|
|
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_mac_send_del_to_client(zvni->vni, macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/*
|
|
|
|
* If there are no neigh associated with the mac delete the mac
|
|
|
|
* else mark it as AUTO for forward reference
|
|
|
|
*/
|
|
|
|
if (!listcount(mac->neigh_list)) {
|
|
|
|
zvni_mac_del(zvni, mac);
|
|
|
|
} else {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle remote MAC delete by kernel; readd the remote MAC if we have it.
|
|
|
|
* This can happen because the remote MAC entries are also added as "dynamic",
|
|
|
|
* so the kernel can ageout the entry.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a remote entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Del remote MAC %s intf %s(%u) VNI %u - readd",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_mac_install(zvni, mac);
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle local MAC delete (on a port or VLAN corresponding to this VNI).
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
u_char sticky;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
|
|
|
* map to a VNI.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_vlan(ifp, br_if, vid);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p doesn't have intf upon local MAC DEL",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Del MAC %s intf %s(%u) VID %u -> VNI %u",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, vid, zvni->vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Is it a local entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Remove MAC from BGP. */
|
|
|
|
sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_mac_send_del_to_client(zvni->vni, macaddr,
|
2017-06-28 10:51:10 +02:00
|
|
|
(sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
/* Update all the neigh entries associated with this mac */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_process_neigh_on_local_mac_del(zvni, mac);
|
2017-07-06 00:03:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are no neigh associated with the mac delete the mac
|
|
|
|
* else mark it as AUTO for forward reference
|
|
|
|
*/
|
|
|
|
if (!listcount(mac->neigh_list)) {
|
|
|
|
zvni_mac_del(zvni, mac);
|
|
|
|
} else {
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-15 07:44:13 +02:00
|
|
|
* Handle local MAC add (on a port or VLAN corresponding to this VNI).
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid,
|
|
|
|
u_char sticky)
|
|
|
|
{
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_mac_t *mac;
|
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
|
|
|
int add = 1;
|
|
|
|
u_char mac_sticky;
|
|
|
|
|
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
|
|
|
* map to a VNI.
|
|
|
|
*/
|
|
|
|
zvni = zvni_map_vlan(ifp, br_if, vid);
|
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
|
|
|
|
sticky ? "sticky " : "",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p doesn't have intf upon local MAC ADD",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u",
|
|
|
|
sticky ? "sticky " : "",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
|
|
|
|
ifp->ifindex, vid, zvni->vni);
|
|
|
|
|
|
|
|
/* If same entry already exists, nothing to do. */
|
|
|
|
mac = zvni_mac_lookup(zvni, macaddr);
|
|
|
|
if (mac) {
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
mac_sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
|
|
|
|
? 1
|
|
|
|
: 0;
|
|
|
|
|
2017-07-06 00:03:14 +02:00
|
|
|
|
2017-06-21 23:25:39 +02:00
|
|
|
/*
|
|
|
|
* return if nothing has changed.
|
|
|
|
* inform bgp if sticky flag has changed
|
|
|
|
* update locally and do not inform bgp if local
|
|
|
|
* parameters like interface has changed
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
if (mac_sticky == sticky
|
|
|
|
&& mac->fwd_info.local.ifindex == ifp->ifindex
|
|
|
|
&& mac->fwd_info.local.vid == vid) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
|
2017-07-17 14:03:14 +02:00
|
|
|
"entry exists and has not changed ",
|
|
|
|
sticky ? "sticky " : "",
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid,
|
|
|
|
zvni->vni);
|
|
|
|
return 0;
|
2017-07-06 00:03:14 +02:00
|
|
|
} else if (mac_sticky != sticky) {
|
2017-06-21 23:25:39 +02:00
|
|
|
add = 1;
|
2017-07-06 00:03:14 +02:00
|
|
|
} else {
|
2017-06-21 23:25:39 +02:00
|
|
|
add = 0; /* This is an update of local
|
|
|
|
interface. */
|
2017-07-06 00:03:14 +02:00
|
|
|
}
|
2017-06-21 21:55:29 +02:00
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
/*
|
|
|
|
* If we have already learned the MAC as a remote sticky
|
|
|
|
* MAC,
|
|
|
|
* this is a operator error and we must log a warning
|
|
|
|
*/
|
2017-06-27 02:55:55 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
|
2017-06-21 21:55:29 +02:00
|
|
|
zlog_warn(
|
|
|
|
"MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d",
|
|
|
|
prefix_mac2str(macaddr, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
inet_ntoa(mac->fwd_info.r_vtep_ip),
|
|
|
|
zvni->vni);
|
2017-06-27 02:55:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mac) {
|
|
|
|
mac = zvni_mac_add(zvni, macaddr);
|
|
|
|
if (!mac) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_err("Failed to add MAC %s intf %s(%u) VID %u",
|
2017-07-17 14:03:14 +02:00
|
|
|
prefix_mac2str(macaddr, buf, sizeof(buf)),
|
|
|
|
ifp->name, ifp->ifindex, vid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set "local" forwarding info. */
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
|
2017-07-06 00:03:14 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
2017-07-17 14:03:14 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
|
2017-07-06 00:03:14 +02:00
|
|
|
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
|
2017-07-17 14:03:14 +02:00
|
|
|
mac->fwd_info.local.ifindex = ifp->ifindex;
|
|
|
|
mac->fwd_info.local.vid = vid;
|
|
|
|
|
|
|
|
if (sticky)
|
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
|
|
|
|
|
|
|
/* Inform BGP if required. */
|
2017-07-06 00:03:14 +02:00
|
|
|
if (add) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_process_neigh_on_local_mac_add(zvni, mac);
|
|
|
|
return zvni_mac_send_add_to_client(zvni->vni, macaddr,
|
2017-07-06 00:03:14 +02:00
|
|
|
sticky);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to delete a remote VTEP for a VNI.
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_remote_vtep_del(struct zserv *client, u_short length,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
u_short l = 0;
|
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
zebra_vtep_t *zvtep;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
zlog_warn("%s: EVPN is not enabled yet we have received a vtep del command",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (zvrf_id(zvrf) != VRF_DEFAULT) {
|
|
|
|
zlog_err("Recv MACIP DEL for non-default VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
s = client->ibuf;
|
|
|
|
|
|
|
|
while (l < length) {
|
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Recv VTEP_DEL %s VNI %u from %s",
|
|
|
|
inet_ntoa(vtep_ip), vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to locate VNI hash upon remote VTEP DEL, "
|
2017-09-18 23:45:34 +02:00
|
|
|
"VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp) {
|
2017-08-30 17:23:01 +02:00
|
|
|
zlog_err(
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP DEL",
|
|
|
|
zvni->vni, zvni);
|
2017-08-14 06:52:04 +02:00
|
|
|
continue;
|
2017-07-20 11:46:28 +02:00
|
|
|
}
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
continue;
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If the remote VTEP does not exist, there's nothing more to
|
|
|
|
* do.
|
|
|
|
* Otherwise, uninstall any remote MACs pointing to this VTEP
|
|
|
|
* and
|
|
|
|
* then, the VTEP entry itself and remove it.
|
|
|
|
*/
|
|
|
|
zvtep = zvni_vtep_find(zvni, &vtep_ip);
|
|
|
|
if (!zvtep)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
zvni_neigh_del_from_vtep(zvni, 1, &vtep_ip);
|
|
|
|
zvni_mac_del_from_vtep(zvni, 1, &vtep_ip);
|
|
|
|
zvni_vtep_uninstall(zvni, &vtep_ip);
|
|
|
|
zvni_vtep_del(zvni, zvtep);
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to add a remote VTEP for a VNI.
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_remote_vtep_add(struct zserv *client, u_short length,
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
u_short l = 0;
|
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
|
|
|
zebra_vni_t *zvni;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
zlog_warn("%s: EVPN not enabled yet we received a vtep_add zapi call",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (zvrf_id(zvrf) != VRF_DEFAULT) {
|
|
|
|
zlog_err("Recv MACIP ADD for non-default VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
s = client->ibuf;
|
|
|
|
|
|
|
|
while (l < length) {
|
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-07-17 14:03:14 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Recv VTEP_ADD %s VNI %u from %s",
|
|
|
|
inet_ntoa(vtep_ip), vni,
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash upon remote VTEP ADD, VNI %u",
|
|
|
|
vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
|
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp) {
|
2017-07-17 14:03:14 +02:00
|
|
|
zlog_err(
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
zif = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
|
2017-08-14 06:52:04 +02:00
|
|
|
/* If the remote VTEP already exists,
|
|
|
|
there's nothing more to do. */
|
2017-07-20 11:46:28 +02:00
|
|
|
if (zvni_vtep_find(zvni, &vtep_ip))
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add remote VTEP, VNI %u zvni %p",
|
|
|
|
vni, zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvni_vtep_install(zvni, &vtep_ip);
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/*
|
|
|
|
* Add/Del gateway macip to evpn
|
|
|
|
* g/w can be:
|
|
|
|
* 1. SVI interface on a vlan aware bridge
|
|
|
|
* 2. SVI interface on a vlan unaware bridge
|
|
|
|
* 3. vrr interface (MACVLAN) associated to a SVI
|
|
|
|
* We advertise macip routes for an interface if it is associated to VxLan vlan
|
|
|
|
*/
|
|
|
|
int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
|
|
|
|
int add)
|
|
|
|
{
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
|
|
|
|
|
|
|
memset(&ip, 0, sizeof(struct ipaddr));
|
|
|
|
memset(&macaddr, 0, sizeof(struct ethaddr));
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-12 23:09:36 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
if (IS_ZEBRA_IF_MACVLAN(ifp)) {
|
|
|
|
struct interface *svi_if =
|
|
|
|
NULL; /* SVI corresponding to the MACVLAN */
|
|
|
|
struct zebra_if *ifp_zif =
|
|
|
|
NULL; /* Zebra daemon specific info for MACVLAN */
|
|
|
|
struct zebra_if *svi_if_zif =
|
|
|
|
NULL; /* Zebra daemon specific info for SVI*/
|
|
|
|
|
|
|
|
ifp_zif = ifp->info;
|
|
|
|
if (!ifp_zif)
|
|
|
|
return -1;
|
|
|
|
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* for a MACVLAN interface the link represents the svi_if
|
|
|
|
*/
|
|
|
|
svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
ifp_zif->link_ifindex);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!svi_if) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_err("MACVLAN %s(%u) without link information",
|
|
|
|
ifp->name, ifp->ifindex);
|
2017-06-28 10:51:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_VLAN(svi_if)) {
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* If it is a vlan aware bridge then the link gives the
|
|
|
|
* bridge information
|
|
|
|
*/
|
|
|
|
struct interface *svi_if_link = NULL;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
svi_if_zif = svi_if->info;
|
2017-08-20 02:28:58 +02:00
|
|
|
if (svi_if_zif) {
|
|
|
|
svi_if_link = if_lookup_by_index_per_ns(
|
2017-08-30 17:23:01 +02:00
|
|
|
zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
svi_if_zif->link_ifindex);
|
2017-08-20 02:28:58 +02:00
|
|
|
zvni = zvni_map_svi(svi_if, svi_if_link);
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
} else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
|
2017-08-20 02:28:58 +02:00
|
|
|
/*
|
|
|
|
* If it is a vlan unaware bridge then svi is the bridge
|
|
|
|
* itself
|
|
|
|
*/
|
2017-06-28 10:51:10 +02:00
|
|
|
zvni = zvni_map_svi(svi_if, svi_if);
|
|
|
|
}
|
|
|
|
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
|
|
|
|
struct zebra_if *svi_if_zif =
|
2017-08-20 02:28:58 +02:00
|
|
|
NULL; /* Zebra daemon specific info for SVI */
|
|
|
|
struct interface *svi_if_link =
|
|
|
|
NULL; /* link info for the SVI = bridge info */
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
svi_if_zif = ifp->info;
|
2017-08-30 17:23:01 +02:00
|
|
|
svi_if_link = if_lookup_by_index_per_ns(
|
|
|
|
zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex);
|
2017-08-20 02:28:58 +02:00
|
|
|
if (svi_if_zif && svi_if_link)
|
|
|
|
zvni = zvni_map_svi(ifp, svi_if_link);
|
2017-06-28 10:51:10 +02:00
|
|
|
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
|
|
|
|
zvni = zvni_map_svi(ifp, ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* check if we are advertising gw macip routes */
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!advertise_gw_macip_enabled(zvni))
|
2017-06-28 10:51:10 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
if (p->family == AF_INET) {
|
|
|
|
ip.ipa_type = IPADDR_V4;
|
|
|
|
memcpy(&(ip.ipaddr_v4), &(p->u.prefix4),
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
} else if (p->family == AF_INET6) {
|
|
|
|
ip.ipa_type = IPADDR_V6;
|
|
|
|
memcpy(&(ip.ipaddr_v6), &(p->u.prefix6),
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
|
|
|
|
else
|
|
|
|
zvni_gw_macip_del(ifp, zvni, &ip);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
|
|
|
* Handle SVI interface going down. At this point, this is a NOP since
|
|
|
|
* the kernel deletes the neighbor entries on this SVI (if any).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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).
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni = zvni_map_svi(ifp, link_if);
|
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni->vxlan_if) {
|
|
|
|
zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
|
|
|
|
zvni->vni, zvni);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("SVI %s(%u) VNI %u is UP, installing neighbors",
|
|
|
|
ifp->name, ifp->ifindex, zvni->vni);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* 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);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* Handle VxLAN interface down - update BGP if required, and do
|
|
|
|
* internal cleanup.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_down(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Intf %s(%u) VNI %u is DOWN",
|
2017-07-17 14:03:14 +02:00
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
assert(zvni->vxlan_if == ifp);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Delete this VNI from BGP. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_del_to_client(zvni->vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all neighbors and MACs, if any. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 1);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface up - update BGP if required.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_up(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Intf %s(%u) VNI %u is UP",
|
2017-07-17 14:03:14 +02:00
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
assert(zvni->vxlan_if == ifp);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If part of a bridge, inform BGP about this VNI. */
|
|
|
|
/* Also, read and populate local MACs and neighbors. */
|
|
|
|
if (zif->brslave_info.br_if) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface delete. Locate and remove entry in hash table
|
|
|
|
* and update BGP, if required.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_del(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("Del VNI %u intf %s(%u)",
|
|
|
|
vni, ifp->name, ifp->ifindex);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to locate VNI hash at del, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Delete VNI from BGP. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_del_to_client(zvni->vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all neighbors and MAC, if any. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
|
|
|
|
zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
|
|
|
zvni_vtep_del_all(zvni, 0);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Delete the hash entry. */
|
2017-09-18 23:45:34 +02:00
|
|
|
if (zvni_del(zvni)) {
|
|
|
|
zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
|
|
|
|
zvni, ifp->name, ifp->ifindex, zvni->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface update - change to tunnel IP, master or VLAN.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
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;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
|
|
|
|
|
|
|
/* Update VNI hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to find VNI hash on update, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Update VNI %u intf %s(%u) VLAN %u local IP %s "
|
2017-07-17 14:03:14 +02:00
|
|
|
"master %u chg 0x%x",
|
2017-09-18 23:45:34 +02:00
|
|
|
vni, ifp->name, ifp->ifindex,
|
2017-07-17 14:03:14 +02:00
|
|
|
vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
|
|
|
|
zif->brslave_info.bridge_ifindex, chgflags);
|
|
|
|
|
2017-07-20 18:54:46 +02:00
|
|
|
/* Removed from bridge? Cleanup and return */
|
2017-07-17 14:03:14 +02:00
|
|
|
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. */
|
2017-09-18 23:45:34 +02:00
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni_vtep_del_all(zvni, 1);
|
2017-07-20 18:54:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle other changes. */
|
|
|
|
if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Remove all existing local neighbors and MACs for this VNI
|
|
|
|
* (including from BGP)
|
|
|
|
*/
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
|
|
|
|
zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->vxlan_if = ifp;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/* Inform BGP, if there is a change of interest. */
|
|
|
|
if (chgflags
|
|
|
|
& (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/* 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)
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
|
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
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;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle VxLAN interface add.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
int zebra_vxlan_if_add(struct interface *ifp)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
zebra_vni_t *zvni;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
vni_t vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vxl->vni;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Add VNI %u intf %s(%u) VLAN %u local IP %s master %u",
|
|
|
|
vni, ifp->name, ifp->ifindex,
|
2017-07-17 14:03:14 +02:00
|
|
|
vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
|
|
|
|
zif->brslave_info.bridge_ifindex);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Create or update VNI hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_add(vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvni) {
|
|
|
|
zlog_err(
|
2017-09-18 23:45:34 +02:00
|
|
|
"Failed to add VNI hash, IF %s(%u) VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zvni->vxlan_if = ifp;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Inform BGP */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_send_add_to_client(zvni);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Read and populate local MACs and neighbors */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_read_mac_neigh(zvni, ifp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of g/w macip
|
|
|
|
* routes
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length,
|
|
|
|
struct zebra_vrf *zvrf)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
|
|
|
zebra_vni_t *zvni = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (zvrf_id(zvrf) != VRF_DEFAULT) {
|
|
|
|
zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
s = client->ibuf;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
|
|
|
STREAM_GET(&vni, s, 3);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
if (!vni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("EVPN gateway macip Adv %s, currently %s",
|
2017-06-28 10:51:10 +02:00
|
|
|
advertise ? "enabled" : "disabled",
|
2017-09-18 23:45:34 +02:00
|
|
|
advertise_gw_macip_enabled(NULL)
|
2017-06-28 10:51:10 +02:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
if (zvrf->advertise_gw_macip == advertise)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zvrf->advertise_gw_macip = advertise;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni))
|
2017-06-28 10:51:10 +02:00
|
|
|
hash_iterate(zvrf->vni_table,
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_gw_macip_add_for_vni_hash, NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
else
|
|
|
|
hash_iterate(zvrf->vni_table,
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_gw_macip_del_for_vni_hash, NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct zebra_l2info_vxlan zl2_info;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2017-09-18 23:45:34 +02:00
|
|
|
"EVPN gateway macip Adv %s on VNI %d , currently %s",
|
2017-06-28 10:51:10 +02:00
|
|
|
advertise ? "enabled" : "disabled", vni,
|
2017-09-18 23:45:34 +02:00
|
|
|
advertise_gw_macip_enabled(zvni)
|
2017-06-28 10:51:10 +02:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni = zvni_lookup(vni);
|
2017-06-28 10:51:10 +02:00
|
|
|
if (!zvni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (zvni->advertise_gw_macip == advertise)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zvni->advertise_gw_macip = advertise;
|
|
|
|
|
2017-07-20 11:46:28 +02:00
|
|
|
ifp = zvni->vxlan_if;
|
|
|
|
if (!ifp)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
2017-08-14 06:52:04 +02:00
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2017-07-20 11:46:28 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
zl2_info = zif->l2info.vxl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
|
2017-06-28 10:51:10 +02:00
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (advertise_gw_macip_enabled(zvni)) {
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add primary SVI MAC-IP */
|
|
|
|
zvni_add_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_add_macip_for_intf(vrr_if, zvni);
|
|
|
|
} else {
|
|
|
|
/* Del primary MAC-IP */
|
|
|
|
zvni_del_macip_for_intf(vlan_if, zvni);
|
|
|
|
|
|
|
|
/* Del VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
|
|
|
zvni_del_macip_for_intf(vrr_if, zvni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-06-28 10:51:10 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to learn (or stop learning) about VNIs and MACs.
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-10-11 14:31:35 +02:00
|
|
|
int zebra_vxlan_advertise_all_vni(struct zserv *client,
|
2017-07-17 14:03:14 +02:00
|
|
|
u_short length, struct zebra_vrf *zvrf)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (zvrf_id(zvrf) != VRF_DEFAULT) {
|
|
|
|
zlog_err("EVPN VNI Adv for non-default VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
s = client->ibuf;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-09-18 23:45:34 +02:00
|
|
|
zlog_debug("EVPN VNI Adv %s, currently %s",
|
2017-07-17 14:03:14 +02:00
|
|
|
advertise ? "enabled" : "disabled",
|
2017-09-18 23:45:34 +02:00
|
|
|
is_evpn_enabled() ? "enabled" : "disabled");
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
if (zvrf->advertise_all_vni == advertise)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
zvrf->advertise_all_vni = advertise;
|
2017-09-18 23:45:34 +02:00
|
|
|
if (is_evpn_enabled()) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Build VNI hash table and inform BGP. */
|
2017-09-18 23:45:34 +02:00
|
|
|
zvni_build_hash_table();
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add all SVI (L3 GW) MACs to BGP*/
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
|
2017-09-18 23:45:34 +02:00
|
|
|
NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Read the MAC FDB */
|
|
|
|
macfdb_read(zvrf->zns);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/* Read neighbors */
|
|
|
|
neigh_read(zvrf->zns);
|
|
|
|
} else {
|
|
|
|
/* Cleanup VTEPs for all VNIs - uninstall from
|
|
|
|
* kernel and free entries.
|
|
|
|
*/
|
|
|
|
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2017-07-17 14:03:14 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate VNI hash table for this VRF and do other initialization.
|
|
|
|
* NOTE: Currently supported only for default VRF.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-07-17 14:03:14 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp,
|
|
|
|
"Zebra VRF VNI Table");
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close all VNI handling */
|
2017-07-17 14:03:14 +02:00
|
|
|
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
|
2017-06-29 15:45:18 +02:00
|
|
|
hash_free(zvrf->vni_table);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|