2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
|
|
|
* Zebra EVPN for VxLAN code
|
|
|
|
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "hash.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "if.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "jhash.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "linklist.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "log.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "prefix.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "stream.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "table.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "vlan.h"
|
|
|
|
#include "vxlan.h"
|
2018-07-07 06:46:46 +02:00
|
|
|
#ifdef GNU_LINUX
|
|
|
|
#include <linux/neighbour.h>
|
|
|
|
#endif
|
2020-10-04 01:12:31 +02:00
|
|
|
#include "lib/printfrr.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
#include "zebra/zebra_router.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "zebra/debug.h"
|
|
|
|
#include "zebra/interface.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "zebra/rib.h"
|
|
|
|
#include "zebra/rt.h"
|
2018-06-19 20:29:05 +02:00
|
|
|
#include "zebra/rt_netlink.h"
|
|
|
|
#include "zebra/zebra_errors.h"
|
|
|
|
#include "zebra/zebra_l2.h"
|
2021-07-27 11:24:40 +02:00
|
|
|
#include "zebra/zebra_l2_bridge_if.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
#include "zebra/zebra_ns.h"
|
|
|
|
#include "zebra/zebra_vrf.h"
|
|
|
|
#include "zebra/zebra_vxlan.h"
|
2021-07-27 09:44:15 +02:00
|
|
|
#include "zebra/zebra_vxlan_private.h"
|
2020-07-23 23:58:45 +02:00
|
|
|
#include "zebra/zebra_evpn.h"
|
|
|
|
#include "zebra/zebra_evpn_mac.h"
|
|
|
|
#include "zebra/zebra_evpn_neigh.h"
|
2020-03-28 01:14:45 +01:00
|
|
|
#include "zebra/zebra_evpn_mh.h"
|
2020-08-10 18:40:48 +02:00
|
|
|
#include "zebra/zebra_evpn_vxlan.h"
|
2019-01-11 19:31:46 +01:00
|
|
|
#include "zebra/zebra_router.h"
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-10-16 23:57:42 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
|
2017-10-08 03:49:27 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
|
2020-07-23 23:58:45 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, L3VNI_MAC, "EVPN L3VNI MAC");
|
2020-07-24 00:30:23 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor");
|
2019-03-26 21:30:29 +01:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
|
2021-09-29 04:01:16 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, EVPN_VTEP, "zebra VxLAN VTEP IP");
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2021-08-19 22:33:53 +02:00
|
|
|
DEFINE_HOOK(zebra_rmac_update,
|
2021-08-20 14:58:24 +02:00
|
|
|
(struct zebra_mac * rmac, struct zebra_l3vni *zl3vni, bool delete,
|
2021-08-19 22:33:53 +02:00
|
|
|
const char *reason),
|
|
|
|
(rmac, zl3vni, delete, reason));
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
|
2021-07-06 16:59:35 +02:00
|
|
|
/* config knobs */
|
|
|
|
static bool accept_bgp_seq = true;
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* Single VXlan Device Global Neigh Table */
|
|
|
|
struct hash *svd_nh_table;
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* static function declarations */
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
|
|
|
|
void **args);
|
2021-08-20 15:01:26 +02:00
|
|
|
static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json);
|
2021-08-19 22:33:53 +02:00
|
|
|
static void zl3vni_print_rmac(struct zebra_mac *zrmac, struct vty *vty,
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json);
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* l3-vni next-hop neigh related APIs */
|
2021-08-20 15:01:26 +02:00
|
|
|
static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *ip);
|
2017-10-08 03:49:27 +02:00
|
|
|
static void *zl3vni_nh_alloc(void *p);
|
2021-08-20 15:01:26 +02:00
|
|
|
static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *vtep_ip,
|
|
|
|
const struct ethaddr *rmac);
|
|
|
|
static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
|
|
|
|
static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
|
|
|
|
static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_neigh *n);
|
2021-04-01 18:00:04 +02:00
|
|
|
static struct zebra_neigh *svd_nh_add(const struct ipaddr *vtep_ip,
|
|
|
|
const struct ethaddr *rmac);
|
|
|
|
static int svd_nh_del(struct zebra_neigh *n);
|
|
|
|
static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
|
|
|
|
static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* l3-vni rmac related APIs */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_mac *zl3vni_rmac_lookup(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
const struct ethaddr *rmac);
|
2017-10-08 03:49:27 +02:00
|
|
|
static void *zl3vni_rmac_alloc(void *p);
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_mac *zl3vni_rmac_add(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
const struct ethaddr *rmac);
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac);
|
|
|
|
static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_mac *zrmac);
|
|
|
|
static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* l3-vni related APIs*/
|
|
|
|
static void *zl3vni_alloc(void *p);
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_l3vni *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
|
|
|
|
static int zl3vni_del(struct zebra_l3vni *zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_build_hash_table(void);
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
|
2019-03-19 21:15:23 +01:00
|
|
|
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2);
|
|
|
|
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp);
|
2021-08-20 14:53:44 +02:00
|
|
|
static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf,
|
|
|
|
struct in_addr sip,
|
|
|
|
struct in_addr mcast_grp);
|
2020-06-28 17:56:03 +02:00
|
|
|
static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2020-05-11 03:02:37 +02:00
|
|
|
bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
return zvrf->dup_addr_detect && zebra_evpn_mh_do_dup_addr_detect();
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* Private functions */
|
2018-05-17 01:24:22 +02:00
|
|
|
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
|
2018-05-21 13:18:18 +02:00
|
|
|
const struct host_rb_entry *hle2)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
if (hle1->p.family < hle2->p.family)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.family > hle2->p.family)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (hle1->p.prefixlen < hle2->p.prefixlen)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.prefixlen > hle2->p.prefixlen)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (hle1->p.family == AF_INET) {
|
|
|
|
if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2018-09-05 23:04:35 +02:00
|
|
|
} else if (hle1->p.family == AF_INET6) {
|
|
|
|
return memcmp(&hle1->p.u.prefix6, &hle2->p.u.prefix6,
|
|
|
|
IPV6_MAX_BYTELEN);
|
2020-09-14 15:35:45 +02:00
|
|
|
} else if (hle1->p.family == AF_EVPN) {
|
2021-07-30 02:23:08 +02:00
|
|
|
uint8_t family1;
|
|
|
|
uint8_t family2;
|
|
|
|
|
|
|
|
/* two (v4/v6) dummy prefixes of route_type BGP_EVPN_AD_ROUTE
|
|
|
|
* are used for all nexthops associated with a non-zero ESI
|
2020-09-14 15:35:45 +02:00
|
|
|
*/
|
2021-07-30 02:23:08 +02:00
|
|
|
family1 = is_evpn_prefix_ipaddr_v4(
|
|
|
|
(const struct prefix_evpn *)&hle1->p)
|
|
|
|
? AF_INET
|
|
|
|
: AF_INET6;
|
|
|
|
family2 = is_evpn_prefix_ipaddr_v4(
|
|
|
|
(const struct prefix_evpn *)&hle2->p)
|
|
|
|
? AF_INET
|
|
|
|
: AF_INET6;
|
|
|
|
|
|
|
|
|
|
|
|
if (family1 < family2)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (family1 > family2)
|
|
|
|
return 1;
|
|
|
|
|
2020-09-14 15:35:45 +02:00
|
|
|
return 0;
|
2018-05-17 01:24:22 +02:00
|
|
|
} else {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: Unexpected family type: %d", __func__,
|
|
|
|
hle1->p.family);
|
2018-05-17 01:24:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_GENERATE(host_rb_tree_entry, host_rb_entry, hl_entry, host_rb_entry_compare);
|
2018-05-17 01:24:22 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, hrbe)
|
2018-05-17 01:24:22 +02:00
|
|
|
count++;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
static int l3vni_rmac_nh_list_cmp(void *p1, void *p2)
|
|
|
|
{
|
|
|
|
const struct ipaddr *vtep_ip1 = p1;
|
|
|
|
const struct ipaddr *vtep_ip2 = p2;
|
|
|
|
|
2023-06-27 00:29:59 +02:00
|
|
|
return ipaddr_cmp(vtep_ip1, vtep_ip2);
|
2021-09-29 04:01:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void l3vni_rmac_nh_free(struct ipaddr *vtep_ip)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_EVPN_VTEP, vtep_ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void l3vni_rmac_nh_list_nh_delete(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_mac *zrmac,
|
|
|
|
struct ipaddr *vtep_ip)
|
|
|
|
{
|
|
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
struct ipaddr *vtep = NULL;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(zrmac->nh_list, node, nnode, vtep)) {
|
|
|
|
if (ipaddr_cmp(vtep, vtep_ip) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node) {
|
|
|
|
l3vni_rmac_nh_free(vtep);
|
|
|
|
list_delete_node(zrmac->nh_list, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Print neighbors for all EVPN.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
|
2017-06-22 01:37:51 +02:00
|
|
|
void **args)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json = NULL, *json_evpn = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-05-15 07:45:55 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
2017-06-22 01:37:51 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
2018-11-04 19:17:29 +01:00
|
|
|
uint32_t print_dup;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (json_object *)args[1];
|
2018-11-04 19:17:29 +01:00
|
|
|
print_dup = (uint32_t)(uintptr_t)args[2];
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2018-08-15 21:56:53 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = hashcount(zevpn->neigh_table);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (print_dup)
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = num_dup_detected_neighs(zevpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
if (json == NULL) {
|
2017-06-22 01:37:51 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, num_neigh);
|
2018-07-07 06:46:46 +02:00
|
|
|
} else {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
|
|
|
json_object_int_add(json_evpn, "numArpNd", num_neigh);
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (!num_neigh) {
|
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +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.
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2017-05-15 07:45:55 +02:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.json = json_evpn;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
|
|
|
|
&wctx);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2020-03-29 17:43:55 +02:00
|
|
|
if (json == NULL)
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_print_neigh_hdr(vty, &wctx);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
if (print_dup)
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table,
|
|
|
|
zebra_evpn_print_dad_neigh_hash, &wctx);
|
2018-11-04 19:17:29 +01:00
|
|
|
else
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash,
|
|
|
|
&wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 10:56:52 +01:00
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Print neighbors for all EVPNs in detail.
|
2018-11-22 10:56:52 +01:00
|
|
|
*/
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_neigh_hash_all_evpn_detail(struct hash_bucket *bucket,
|
2018-11-22 10:56:52 +01:00
|
|
|
void **args)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json = NULL, *json_evpn = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-22 10:56:52 +01:00
|
|
|
uint32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
uint32_t print_dup;
|
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (json_object *)args[1];
|
|
|
|
print_dup = (uint32_t)(uintptr_t)args[2];
|
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2018-11-22 10:56:52 +01:00
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = hashcount(zevpn->neigh_table);
|
2018-11-22 10:56:52 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (print_dup && num_dup_detected_neighs(zevpn) == 0)
|
2018-11-22 10:56:52 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (json == NULL) {
|
|
|
|
vty_out(vty,
|
|
|
|
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, num_neigh);
|
2018-11-22 10:56:52 +01:00
|
|
|
} else {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
|
|
|
json_object_int_add(json_evpn, "numArpNd", num_neigh);
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
|
2018-11-22 10:56:52 +01:00
|
|
|
}
|
|
|
|
if (!num_neigh) {
|
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2018-11-22 10:56:52 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2018-11-22 10:56:52 +01:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.json = json_evpn;
|
2018-11-22 10:56:52 +01:00
|
|
|
|
|
|
|
if (print_dup)
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zevpn->neigh_table,
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_print_dad_neigh_hash_detail, &wctx);
|
2018-11-22 10:56:52 +01:00
|
|
|
else
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table,
|
|
|
|
zebra_evpn_print_neigh_hash_detail, &wctx);
|
2018-11-22 10:56:52 +01:00
|
|
|
|
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2018-11-22 10:56:52 +01:00
|
|
|
}
|
|
|
|
|
2017-10-17 01:51:32 +02:00
|
|
|
/* print a specific next hop for an l3vni */
|
2021-08-20 15:01:26 +02:00
|
|
|
static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json_hosts = NULL;
|
2018-05-17 14:18:23 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "Ip: %s\n",
|
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
|
|
|
vty_out(vty, " RMAC: %s\n",
|
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2021-04-08 20:27:57 +02:00
|
|
|
if (n->refcnt)
|
|
|
|
/* SVD neigh */
|
|
|
|
vty_out(vty, " Refcount: %u\n", n->refcnt);
|
|
|
|
else {
|
|
|
|
vty_out(vty, " Refcount: %d\n",
|
|
|
|
rb_host_count(&n->host_rb));
|
|
|
|
vty_out(vty, " Prefixes:\n");
|
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
|
|
|
vty_out(vty, " %pFX\n", &hle->p);
|
|
|
|
}
|
2017-10-17 13:32:31 +02:00
|
|
|
} else {
|
|
|
|
json_hosts = json_object_new_array();
|
|
|
|
json_object_string_add(
|
|
|
|
json, "ip", ipaddr2str(&(n->ip), buf2, sizeof(buf2)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json, "routerMac",
|
2017-10-17 13:32:31 +02:00
|
|
|
prefix_mac2str(&n->emac, buf2, sizeof(buf2)));
|
2021-04-08 20:27:57 +02:00
|
|
|
if (n->refcnt)
|
|
|
|
/* SVD neigh */
|
|
|
|
json_object_int_add(json, "refCount", n->refcnt);
|
|
|
|
else {
|
|
|
|
json_object_int_add(json, "refCount",
|
|
|
|
rb_host_count(&n->host_rb));
|
|
|
|
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
|
|
|
json_object_array_add(
|
|
|
|
json_hosts,
|
|
|
|
json_object_new_string(prefix2str(
|
|
|
|
&hle->p, buf2, sizeof(buf2))));
|
|
|
|
json_object_object_add(json, "prefixList", json_hosts);
|
|
|
|
}
|
2017-10-17 13:32:31 +02:00
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print a specific RMAC entry */
|
2021-08-19 22:33:53 +02:00
|
|
|
static void zl3vni_print_rmac(struct zebra_mac *zrmac, struct vty *vty,
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
2021-10-18 20:51:35 +02:00
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct ipaddr *vtep = NULL;
|
|
|
|
json_object *json_nhs = NULL;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
if (!json) {
|
2021-10-18 20:43:29 +02:00
|
|
|
vty_out(vty, "MAC: %pEA\n", &zrmac->macaddr);
|
2020-10-21 19:57:06 +02:00
|
|
|
vty_out(vty, " Remote VTEP: %pI4\n",
|
|
|
|
&zrmac->fwd_info.r_vtep_ip);
|
2017-10-17 14:25:47 +02:00
|
|
|
} else {
|
2021-10-18 20:51:35 +02:00
|
|
|
json_nhs = json_object_new_array();
|
2021-10-18 20:43:29 +02:00
|
|
|
json_object_string_addf(json, "routerMac", "%pEA",
|
|
|
|
&zrmac->macaddr);
|
2021-11-18 09:58:23 +01:00
|
|
|
json_object_string_addf(json, "vtepIp", "%pI4",
|
|
|
|
&zrmac->fwd_info.r_vtep_ip);
|
2021-10-18 20:51:35 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(zrmac->nh_list, node, vtep)) {
|
2021-10-18 20:43:29 +02:00
|
|
|
json_object_array_add(json_nhs, json_object_new_stringf(
|
|
|
|
"%pIA", vtep));
|
2021-10-18 20:51:35 +02:00
|
|
|
}
|
|
|
|
json_object_object_add(json, "nexthops", json_nhs);
|
2017-10-17 14:25:47 +02:00
|
|
|
}
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Print MACs for all EVPNs.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json = NULL, *json_evpn = NULL;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json_mac = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-05-15 07:45:55 +02:00
|
|
|
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
|
|
|
|
2020-04-08 07:57:15 +02:00
|
|
|
vty = wctx->vty;
|
|
|
|
json = wctx->json;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx->zevpn = zevpn;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
|
|
|
/*We are iterating over a new VNI, set the count to 0*/
|
|
|
|
wctx->count = 0;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_valid_macs(zevpn);
|
2017-05-15 07:45:55 +02:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
if (wctx->print_dup)
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_dup_detected_macs(zevpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (json) {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
2017-06-22 01:37:51 +02:00
|
|
|
json_mac = json_object_new_object();
|
2020-07-23 23:51:10 +02:00
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
|
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",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, num_macs);
|
2020-03-29 17:43:55 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
|
|
|
|
vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
|
|
|
|
"Type", "Flags", "Intf/Remote ES/VTEP",
|
|
|
|
"VLAN", "Seq #'s");
|
2017-06-22 01:37:51 +02:00
|
|
|
} else
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numMacs", num_macs);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (!num_macs) {
|
|
|
|
if (json) {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numMacs", num_macs);
|
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* assign per-evpn to wctx->json object to fill macs
|
|
|
|
* under the evpn. Re-assign primary json object to fill
|
|
|
|
* next evpn information.
|
2017-06-22 01:37:51 +02:00
|
|
|
*/
|
|
|
|
wctx->json = json_mac;
|
2018-11-04 19:17:29 +01:00
|
|
|
if (wctx->print_dup)
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash,
|
|
|
|
wctx);
|
2018-11-04 19:17:29 +01:00
|
|
|
else
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx->json = json;
|
|
|
|
if (json) {
|
|
|
|
if (wctx->count)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json_evpn, "macs", json_mac);
|
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Print MACs in detail for all EVPNs.
|
2018-11-22 09:18:10 +01:00
|
|
|
*/
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_print_mac_hash_all_evpn_detail(struct hash_bucket *bucket,
|
2018-11-22 09:18:10 +01:00
|
|
|
void *ctxt)
|
|
|
|
{
|
|
|
|
struct vty *vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json = NULL, *json_evpn = NULL;
|
2018-11-22 09:18:10 +01:00
|
|
|
json_object *json_mac = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-22 09:18:10 +01:00
|
|
|
uint32_t num_macs;
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
2020-04-08 07:57:15 +02:00
|
|
|
vty = wctx->vty;
|
|
|
|
json = wctx->json;
|
2018-11-22 09:18:10 +01:00
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2018-11-22 09:18:10 +01:00
|
|
|
if (json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx->zevpn = zevpn;
|
2018-11-22 09:18:10 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/*We are iterating over a new EVPN, set the count to 0*/
|
2018-11-22 09:18:10 +01:00
|
|
|
wctx->count = 0;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_valid_macs(zevpn);
|
2018-11-22 09:18:10 +01:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (wctx->print_dup && (num_dup_detected_macs(zevpn) == 0))
|
2018-11-22 09:18:10 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
2018-11-22 09:18:10 +01:00
|
|
|
json_mac = json_object_new_object();
|
2020-07-23 23:51:10 +02:00
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
|
2018-11-22 09:18:10 +01: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",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, num_macs);
|
2018-11-22 09:18:10 +01:00
|
|
|
} else
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numMacs", num_macs);
|
2018-11-22 09:18:10 +01:00
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
/* assign per-evpn to wctx->json object to fill macs
|
|
|
|
* under the evpn. Re-assign primary json object to fill
|
|
|
|
* next evpn information.
|
2018-11-22 09:18:10 +01:00
|
|
|
*/
|
|
|
|
wctx->json = json_mac;
|
|
|
|
if (wctx->print_dup)
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table,
|
|
|
|
zebra_evpn_print_dad_mac_hash_detail, wctx);
|
2018-11-22 09:18:10 +01:00
|
|
|
else
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash_detail,
|
|
|
|
wctx);
|
2018-11-22 09:18:10 +01:00
|
|
|
wctx->json = json;
|
|
|
|
if (json) {
|
|
|
|
if (wctx->count)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json_evpn, "macs", json_mac);
|
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2018-11-22 09:18:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct nh_walk_ctx *wctx = NULL;
|
|
|
|
struct vty *vty = NULL;
|
2020-07-23 23:51:10 +02:00
|
|
|
struct json_object *json_evpn = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct json_object *json_nh = NULL;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
2017-10-13 10:13:48 +02:00
|
|
|
char buf2[INET6_ADDRSTRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
wctx = (struct nh_walk_ctx *)ctx;
|
|
|
|
vty = wctx->vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = wctx->json;
|
|
|
|
if (json_evpn)
|
2017-10-08 03:49:27 +02:00
|
|
|
json_nh = json_object_new_object();
|
2021-08-20 15:01:26 +02:00
|
|
|
n = (struct zebra_neigh *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!json_evpn) {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n",
|
2017-10-13 10:13:48 +02:00
|
|
|
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
|
2017-11-15 10:01:00 +01:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json_nh, "nexthopIp",
|
2017-10-17 12:48:06 +02:00
|
|
|
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json_nh, "routerMac",
|
2017-10-08 03:49:27 +02:00
|
|
|
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json_evpn,
|
2017-10-17 12:48:06 +02:00
|
|
|
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
|
|
|
|
json_nh);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
static void zl3vni_print_nh_all_table(struct hash *nh_table, vni_t vni,
|
|
|
|
struct vty *vty, json_object *json)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
|
|
|
uint32_t num_nh = 0;
|
2017-10-17 12:48:06 +02:00
|
|
|
struct nh_walk_ctx wctx;
|
2017-10-13 10:13:48 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
2021-04-08 20:27:57 +02:00
|
|
|
json_object *json_evpn = NULL;
|
|
|
|
bool is_svd = false;
|
|
|
|
const char *svd_str = "Global SVD Table";
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
if (vni == 0)
|
|
|
|
is_svd = true;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
num_nh = hashcount(nh_table);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
if (!num_nh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
2021-04-08 20:27:57 +02:00
|
|
|
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", vni);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (json == NULL) {
|
2021-04-08 20:27:57 +02:00
|
|
|
if (is_svd)
|
|
|
|
vty_out(vty, "\n%s #Next-Hops %u\n\n", svd_str, num_nh);
|
|
|
|
else
|
|
|
|
vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", vni, num_nh);
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
|
2017-10-13 10:13:48 +02:00
|
|
|
} else
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numNextHops", num_nh);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2017-10-17 12:48:06 +02:00
|
|
|
wctx.vty = vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.json = json_evpn;
|
2021-04-08 20:27:57 +02:00
|
|
|
hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
|
2017-10-17 12:48:06 +02:00
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
|
|
|
|
void **args)
|
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
|
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (struct json_object *)args[1];
|
|
|
|
|
|
|
|
zl3vni = (struct zebra_l3vni *)bucket->data;
|
|
|
|
|
|
|
|
zl3vni_print_nh_all_table(zl3vni->nh_table, zl3vni->vni, vty, json);
|
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
|
2017-10-17 13:59:42 +02:00
|
|
|
void **args)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json_evpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_rmacs;
|
2017-10-17 13:59:42 +02:00
|
|
|
struct rmac_walk_ctx wctx;
|
2017-10-08 03:49:27 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
2017-10-17 13:59:42 +02:00
|
|
|
vty = (struct vty *)args[0];
|
|
|
|
json = (struct json_object *)args[1];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
num_rmacs = hashcount(zl3vni->rmac_table);
|
|
|
|
if (!num_rmacs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (json) {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn = json_object_new_object();
|
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (json == NULL) {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs);
|
|
|
|
vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numRmacs", num_rmacs);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* assign per-vni to wctx->json object to fill macs
|
|
|
|
* under the vni. Re-assign primary json object to fill
|
|
|
|
* next vni information.
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2017-10-17 13:59:42 +02:00
|
|
|
wctx.vty = vty;
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.json = json_evpn;
|
2017-10-17 13:59:42 +02:00
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
|
|
|
|
if (json)
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct rmac_walk_ctx *wctx = NULL;
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
struct json_object *json = NULL;
|
|
|
|
struct json_object *json_rmac = NULL;
|
2020-10-21 19:57:06 +02:00
|
|
|
char buf[PREFIX_STRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
wctx = (struct rmac_walk_ctx *)ctx;
|
|
|
|
vty = wctx->vty;
|
|
|
|
json = wctx->json;
|
|
|
|
if (json)
|
|
|
|
json_rmac = json_object_new_object();
|
2021-08-19 22:33:53 +02:00
|
|
|
zrmac = (struct zebra_mac *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!json) {
|
2020-10-21 19:57:06 +02:00
|
|
|
vty_out(vty, "%-17s %-21pI4\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
|
2020-10-21 19:57:06 +02:00
|
|
|
&zrmac->fwd_info.r_vtep_ip);
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json_rmac, "routerMac",
|
2017-10-08 03:49:27 +02:00
|
|
|
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)));
|
2021-11-18 09:58:23 +01:00
|
|
|
json_object_string_addf(json_rmac, "vtepIp", "%pI4",
|
|
|
|
&zrmac->fwd_info.r_vtep_ip);
|
2017-10-17 13:59:42 +02:00
|
|
|
json_object_object_add(
|
|
|
|
json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
|
|
|
|
json_rmac);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print a specific L3 VNI entry */
|
2021-08-20 14:58:24 +02:00
|
|
|
static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2020-10-21 19:57:06 +02:00
|
|
|
char buf[PREFIX_STRLEN];
|
2017-10-08 03:49:27 +02:00
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json_evpn_list = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct listnode *node = NULL, *nnode = NULL;
|
|
|
|
|
|
|
|
vty = ctx[0];
|
|
|
|
json = ctx[1];
|
|
|
|
|
|
|
|
if (!json) {
|
|
|
|
vty_out(vty, "VNI: %u\n", zl3vni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Type: %s\n", "L3");
|
|
|
|
vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni));
|
2021-07-27 11:24:40 +02:00
|
|
|
vty_out(vty, " Vlan: %u\n", zl3vni->vid);
|
|
|
|
vty_out(vty, " Bridge: %s\n",
|
|
|
|
zl3vni->bridge_if ? zl3vni->bridge_if->name : "-");
|
2020-10-21 19:57:06 +02:00
|
|
|
vty_out(vty, " Local Vtep Ip: %pI4\n",
|
|
|
|
&zl3vni->local_vtep_ip);
|
2017-10-08 03:49:27 +02:00
|
|
|
vty_out(vty, " Vxlan-Intf: %s\n",
|
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
|
|
|
vty_out(vty, " SVI-If: %s\n", zl3vni_svi_if_name(zl3vni));
|
|
|
|
vty_out(vty, " State: %s\n", zl3vni_state2str(zl3vni));
|
2018-02-06 23:28:22 +01:00
|
|
|
vty_out(vty, " VNI Filter: %s\n",
|
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none");
|
zebra: print rmac and sys mac values
"show vrf vni" and "show evpn vni <l3vni>" commands
need to display correct router mac value.
"show evpn vni <l3vni>" detail l3vni needs to display
system mac as in PIP scenario value can be different.
Syste MAC would be derived from SVI interface MAC wherelse
Router MAC would be derived from macvlan interface MAC value.
Ticket:CM-26710
Reviewed By:CCR-9334
Testing Done:
TORC11# show evpn vni 4001
VNI: 4001
Type: L3
Tenant VRF: vrf1
Local Vtep Ip: 36.0.0.11
Vxlan-Intf: vx-4001
SVI-If: vlan4001
State: Up
VNI Filter: none
System MAC: 00:02:00:00:00:2e
Router MAC: 44:38:39:ff:ff:01
L2 VNIs: 1000
TORC11# show vrf vni
VRF VNI VxLAN IF L3-SVI State Rmac
vrf1 4001 vx-4001 vlan4001 Up 44:38:39:ff:ff:01
TORC11# show evpn vni 4001 json
{
"vni":4001,
"type":"L3",
"localVtepIp":"36.0.0.11",
"vxlanIntf":"vx-4001",
"sviIntf":"vlan4001",
"state":"Up",
"vrf":"vrf1",
"sysMac":"00:02:00:00:00:2e",
"routerMac":"44:38:39:ff:ff:01",
"vniFilter":"none",
"l2Vnis":[
1000,
]
}
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-10-15 02:46:10 +02:00
|
|
|
vty_out(vty, " System MAC: %s\n",
|
|
|
|
zl3vni_sysmac2str(zl3vni, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " Router MAC: %s\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, " L2 VNIs: ");
|
2020-07-23 23:51:10 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn))
|
|
|
|
vty_out(vty, "%u ", zevpn->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
vty_out(vty, "\n");
|
|
|
|
} else {
|
2020-07-23 23:51:10 +02:00
|
|
|
json_evpn_list = json_object_new_array();
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object_int_add(json, "vni", zl3vni->vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "type", "L3");
|
zebra: fix JSON fields for show evpn vni detail
Few of the JSON field in show evpn vni detail command is
confusing and a few fields were missing. Following is the
updated output.
primary# show evpn vni detail json
[
{
"vni":200,
"type":"L2",
"vrf":"default",
"tenantVrf":"default",
"vxlanInterface":"vni200",
"ifindex":19,
"vxlanIfindex":19,
"sviInterface":"br200",
"sviIfindex":18,
"vtepIp":"2.2.2.1",
"mcastGroup":"0.0.0.0",
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"numMacs":0,
"numArpNd":0,
"numRemoteVteps":1,
"remoteVteps":[
{
"ip":"2.2.2.2",
"flood":"HER"
}
]
},
{
"vni":100,
"type":"L3",
"vrf":"default",
"tenantVrf":"default",
"localVtepIp":"2.2.2.1",
"vxlanIntf":"vni100",
"sviIntf":"br100",
"state":"Up",
"sysMac":"aa:bb:cc:dd:ee:f1",
"routerMac":"aa:bb:cc:dd:ee:f1",
"vniFilter":"none",
"l2Vnis":[
20,
30,
200
]
}
]
Signed-off-by: Pooja Jagadeesh Doijode <pdoijode@nvidia.com>
2023-01-26 19:31:08 +01:00
|
|
|
#if CONFDATE > 20240210
|
|
|
|
CPP_NOTICE("Drop `vrf` from JSON outputs")
|
|
|
|
#endif
|
|
|
|
json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
|
|
|
|
json_object_string_add(json, "tenantVrf",
|
|
|
|
zl3vni_vrf_name(zl3vni));
|
2021-11-18 09:58:23 +01:00
|
|
|
json_object_string_addf(json, "localVtepIp", "%pI4",
|
|
|
|
&zl3vni->local_vtep_ip);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "vxlanIntf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(json, "sviIntf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_svi_if_name(zl3vni));
|
|
|
|
json_object_string_add(json, "state", zl3vni_state2str(zl3vni));
|
zebra: print rmac and sys mac values
"show vrf vni" and "show evpn vni <l3vni>" commands
need to display correct router mac value.
"show evpn vni <l3vni>" detail l3vni needs to display
system mac as in PIP scenario value can be different.
Syste MAC would be derived from SVI interface MAC wherelse
Router MAC would be derived from macvlan interface MAC value.
Ticket:CM-26710
Reviewed By:CCR-9334
Testing Done:
TORC11# show evpn vni 4001
VNI: 4001
Type: L3
Tenant VRF: vrf1
Local Vtep Ip: 36.0.0.11
Vxlan-Intf: vx-4001
SVI-If: vlan4001
State: Up
VNI Filter: none
System MAC: 00:02:00:00:00:2e
Router MAC: 44:38:39:ff:ff:01
L2 VNIs: 1000
TORC11# show vrf vni
VRF VNI VxLAN IF L3-SVI State Rmac
vrf1 4001 vx-4001 vlan4001 Up 44:38:39:ff:ff:01
TORC11# show evpn vni 4001 json
{
"vni":4001,
"type":"L3",
"localVtepIp":"36.0.0.11",
"vxlanIntf":"vx-4001",
"sviIntf":"vlan4001",
"state":"Up",
"vrf":"vrf1",
"sysMac":"00:02:00:00:00:2e",
"routerMac":"44:38:39:ff:ff:01",
"vniFilter":"none",
"l2Vnis":[
1000,
]
}
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2019-10-15 02:46:10 +02:00
|
|
|
json_object_string_add(
|
|
|
|
json, "sysMac",
|
|
|
|
zl3vni_sysmac2str(zl3vni, buf, sizeof(buf)));
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json, "routerMac",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2018-02-06 23:28:22 +01:00
|
|
|
json_object_string_add(
|
|
|
|
json, "vniFilter",
|
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none");
|
2020-07-23 23:51:10 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn)) {
|
|
|
|
json_object_array_add(json_evpn_list,
|
|
|
|
json_object_new_int(zevpn->vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, "l2Vnis", json_evpn_list);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print a L3 VNI hash entry */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[])
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
|
|
|
json_object *json = NULL;
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object *json_evpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-17 11:59:35 +02:00
|
|
|
vty = (struct vty *)ctx[0];
|
|
|
|
json = (json_object *)ctx[1];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)bucket->data;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!json) {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vni, "L3", zl3vni_vxlan_if_name(zl3vni),
|
2017-11-15 10:01:00 +01:00
|
|
|
hashcount(zl3vni->rmac_table),
|
|
|
|
hashcount(zl3vni->nh_table), "n/a",
|
|
|
|
zl3vni_vrf_name(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-10-17 11:59:35 +02:00
|
|
|
char vni_str[VNI_STR_LEN];
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
|
|
|
|
json_evpn = json_object_new_object();
|
|
|
|
json_object_int_add(json_evpn, "vni", zl3vni->vni);
|
|
|
|
json_object_string_add(json_evpn, "vxlanIf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numMacs",
|
2017-11-15 10:01:00 +01:00
|
|
|
hashcount(zl3vni->rmac_table));
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_int_add(json_evpn, "numArpNd",
|
2017-11-15 10:01:00 +01:00
|
|
|
hashcount(zl3vni->nh_table));
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_string_add(json_evpn, "numRemoteVteps", "n/a");
|
|
|
|
json_object_string_add(json_evpn, "type", "L3");
|
|
|
|
json_object_string_add(json_evpn, "tenantVrf",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_vrf_name(zl3vni));
|
2020-07-23 23:51:10 +02:00
|
|
|
json_object_object_add(json, vni_str, json_evpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:33:43 +01:00
|
|
|
/* print a L3 VNI hash entry in detail*/
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
|
2018-11-15 18:33:43 +01:00
|
|
|
{
|
|
|
|
struct vty *vty = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2019-11-22 01:18:04 +01:00
|
|
|
json_object *json_array = NULL;
|
2018-11-15 18:33:43 +01:00
|
|
|
bool use_json = false;
|
2020-08-10 18:40:48 +02:00
|
|
|
struct zebra_evpn_show *zes = data;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
vty = zes->vty;
|
2019-11-22 01:18:04 +01:00
|
|
|
json_array = zes->json;
|
|
|
|
use_json = zes->use_json;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)bucket->data;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
2019-11-22 01:18:04 +01:00
|
|
|
zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni,
|
|
|
|
use_json, json_array);
|
|
|
|
|
|
|
|
if (!use_json)
|
|
|
|
vty_out(vty, "\n");
|
2018-11-15 18:33:43 +01:00
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
static int zvni_map_to_svi_ns(struct ns *ns,
|
2019-09-27 15:45:42 +02:00
|
|
|
void *_in_param,
|
|
|
|
void **_p_ifp)
|
|
|
|
{
|
2019-12-20 17:51:37 +01:00
|
|
|
struct zebra_ns *zns = ns->info;
|
2019-09-27 15:45:42 +02:00
|
|
|
struct route_node *rn;
|
|
|
|
struct zebra_from_svi_param *in_param =
|
|
|
|
(struct zebra_from_svi_param *)_in_param;
|
|
|
|
struct zebra_l2info_vlan *vl;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct interface **p_ifp = (struct interface **)_p_ifp;
|
|
|
|
struct zebra_if *zif;
|
|
|
|
|
2022-02-06 04:59:09 +01:00
|
|
|
assert(in_param && p_ifp);
|
2019-09-27 15:45:42 +02:00
|
|
|
|
|
|
|
/* TODO: Optimize with a hash. */
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
/* Check oper status of the SVI. */
|
|
|
|
if (!tmp_if || !if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|
|
|
|
|| zif->link != in_param->br_if)
|
|
|
|
continue;
|
|
|
|
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
|
|
|
|
|
|
|
|
if (vl->vid == in_param->vid) {
|
2022-02-06 04:59:09 +01:00
|
|
|
*p_ifp = tmp_if;
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_STOP;
|
2019-09-27 15:45:42 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_CONTINUE;
|
2019-09-27 15:45:42 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +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 interface
|
|
|
|
* itself
|
2018-11-15 18:33:43 +01:00
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2020-07-24 00:30:23 +02:00
|
|
|
struct interface *tmp_if = NULL;
|
2020-08-10 18:40:48 +02:00
|
|
|
struct zebra_if *zif;
|
2019-09-27 15:45:42 +02:00
|
|
|
struct zebra_from_svi_param in_param;
|
|
|
|
struct interface **p_ifp;
|
2020-08-10 18:40:48 +02:00
|
|
|
/* Defensive check, caller expected to invoke only with valid bridge. */
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
2021-07-27 09:47:52 +02:00
|
|
|
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
|
2020-08-10 18:40:48 +02:00
|
|
|
/* Check oper status of the SVI. */
|
2019-09-27 15:45:42 +02:00
|
|
|
if (!in_param.bridge_vlan_aware)
|
2020-08-10 18:40:48 +02:00
|
|
|
return if_is_operative(br_if) ? br_if : NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-09-27 15:45:42 +02:00
|
|
|
in_param.vid = vid;
|
|
|
|
in_param.br_if = br_if;
|
|
|
|
in_param.zif = NULL;
|
|
|
|
p_ifp = &tmp_if;
|
2020-02-06 09:33:21 +01:00
|
|
|
/* Identify corresponding VLAN interface. */
|
2019-12-20 17:51:37 +01:00
|
|
|
ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param,
|
|
|
|
(void **)p_ifp);
|
2019-09-27 15:45:42 +02:00
|
|
|
return tmp_if;
|
2020-08-10 18:40:48 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2021-07-27 10:10:48 +02:00
|
|
|
int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
|
2020-08-10 18:40:48 +02:00
|
|
|
{
|
2021-07-27 11:24:40 +02:00
|
|
|
zevpn->vid = 0;
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */);
|
2021-07-27 11:24:40 +02:00
|
|
|
zevpn_bridge_if_set(zevpn, zevpn->bridge_if, false /* set */);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
/* Remove references to the BUM mcast grp */
|
|
|
|
zebra_vxlan_sg_deref(zevpn->local_vtep_ip, zevpn->mcast_grp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
return zebra_evpn_del(zevpn);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
|
2021-07-27 10:48:05 +02:00
|
|
|
static int zevpn_build_vni_hash_table(struct zebra_if *zif,
|
|
|
|
struct zebra_vxlan_vni *vnip, void *arg)
|
|
|
|
{
|
|
|
|
vni_t vni;
|
|
|
|
struct zebra_evpn *zevpn;
|
|
|
|
struct zebra_l3vni *zl3vni;
|
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
2021-07-27 11:24:40 +02:00
|
|
|
struct interface *br_if;
|
2021-07-27 10:48:05 +02:00
|
|
|
|
|
|
|
ifp = zif->ifp;
|
|
|
|
vxl = &zif->l2info.vxl;
|
|
|
|
vni = vnip->vni;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Build vni table for vni %u for Intf %s", vni,
|
|
|
|
ifp->name);
|
|
|
|
|
|
|
|
/* L3-VNI and L2-VNI are handled seperately */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"create L3-VNI hash for Intf %s(%u) L3-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
|
|
|
|
/* associate with vxlan_if */
|
|
|
|
zl3vni->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zl3vni->vxlan_if = ifp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we need to associate with SVI.
|
|
|
|
* we can associate with svi-if only after association
|
|
|
|
* with vxlan-intf is complete
|
|
|
|
*/
|
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
|
|
|
|
|
|
|
/* Associate l3vni to mac-vlan and extract VRR MAC */
|
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"create l3vni %u svi_if %s mac_vlan_if %s", vni,
|
|
|
|
zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
|
|
|
|
zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name
|
|
|
|
: "NIL");
|
|
|
|
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4",
|
|
|
|
ifp->name, ifp->ifindex, vni, &vxl->vtep_ip);
|
|
|
|
|
2021-07-27 18:29:00 +02:00
|
|
|
/*
|
|
|
|
* EVPN hash entry is expected to exist, if the BGP process is
|
|
|
|
* killed
|
|
|
|
*/
|
2021-07-27 10:48:05 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
|
|
|
if (zevpn) {
|
|
|
|
zlog_debug(
|
|
|
|
"EVPN hash already present for IF %s(%u) L2-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP if intf is up and mapped to
|
|
|
|
* bridge.
|
|
|
|
*/
|
|
|
|
if (if_is_operative(ifp) && zif->brslave_info.br_if)
|
|
|
|
zebra_evpn_send_add_to_client(zevpn);
|
|
|
|
|
|
|
|
/* Send Local MAC-entries to client */
|
|
|
|
zebra_evpn_send_mac_list_to_client(zevpn);
|
|
|
|
|
|
|
|
/* Send Loval Neighbor entries to client */
|
|
|
|
zebra_evpn_send_neigh_to_client(zevpn);
|
|
|
|
} else {
|
|
|
|
zevpn = zebra_evpn_add(vni);
|
|
|
|
if (!zevpn) {
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
|
|
|
|
ifp->name, ifp->ifindex, vni);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-10 00:51:22 +01:00
|
|
|
if (zevpn->local_vtep_ip.s_addr !=
|
|
|
|
vxl->vtep_ip.s_addr ||
|
|
|
|
zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) {
|
2021-07-27 10:48:05 +02:00
|
|
|
zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
|
|
|
|
zevpn->mcast_grp);
|
|
|
|
zebra_vxlan_sg_ref(vxl->vtep_ip,
|
|
|
|
vnip->mcast_grp);
|
|
|
|
zevpn->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
zevpn->mcast_grp = vnip->mcast_grp;
|
|
|
|
/* on local vtep-ip check if ES
|
|
|
|
* orig-ip needs to be updated
|
|
|
|
*/
|
|
|
|
zebra_evpn_es_set_base_evpn(zevpn);
|
|
|
|
}
|
|
|
|
zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
|
2021-07-27 11:24:40 +02:00
|
|
|
br_if = zif->brslave_info.br_if;
|
|
|
|
zevpn_bridge_if_set(zevpn, br_if, true /* set */);
|
|
|
|
vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if);
|
2021-07-27 10:48:05 +02:00
|
|
|
if (vlan_if) {
|
2021-07-27 11:24:40 +02:00
|
|
|
zevpn->vid = vnip->access_vlan;
|
2021-07-27 10:48:05 +02:00
|
|
|
zevpn->svi_if = vlan_if;
|
|
|
|
zevpn->vrf_id = vlan_if->vrf->vrf_id;
|
|
|
|
zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort(zl3vni->l2vnis,
|
|
|
|
zevpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP if intf is up and mapped to
|
|
|
|
* bridge.
|
|
|
|
*/
|
|
|
|
if (if_is_operative(ifp) && zif->brslave_info.br_if)
|
|
|
|
zebra_evpn_send_add_to_client(zevpn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
static int zevpn_build_hash_table_zns(struct ns *ns,
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
void *param_in __attribute__((unused)),
|
|
|
|
void **param_out __attribute__((unused)))
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2019-12-20 17:51:37 +01:00
|
|
|
struct zebra_ns *zns = ns->info;
|
2017-09-18 23:45:34 +02:00
|
|
|
struct route_node *rn;
|
2017-05-15 07:44:13 +02:00
|
|
|
struct interface *ifp;
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_get_evpn();
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* Walk VxLAN interfaces and create EVPN hash. */
|
2017-09-18 23:45:34 +02:00
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
2017-05-15 07:44:13 +02:00
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
2017-05-15 07:44:13 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
vxl = &zif->l2info.vxl;
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
|
|
|
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-07-27 10:48:05 +02:00
|
|
|
"Intf %s(%u) link not in same "
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
"namespace than BGP EVPN core instance ",
|
2021-07-27 10:48:05 +02:00
|
|
|
ifp->name, ifp->ifindex);
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-07-27 10:48:05 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Building vni table for %s-if %s",
|
|
|
|
IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd",
|
|
|
|
ifp->name);
|
2019-08-02 08:33:24 +02:00
|
|
|
|
2021-07-27 10:48:05 +02:00
|
|
|
zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table,
|
|
|
|
NULL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_CONTINUE;
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the VNI hash table by going over the VxLAN interfaces. This
|
|
|
|
* is called when EVPN (advertise-all-vni) is enabled.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void zevpn_build_hash_table(void)
|
|
|
|
{
|
2022-05-08 15:07:42 +02:00
|
|
|
ns_walk_func(zevpn_build_hash_table_zns, NULL, NULL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Cleanup EVPN/VTEP and update kernel
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
static void zebra_evpn_vxlan_cleanup_all(struct hash_bucket *bucket, void *arg)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2022-02-19 01:18:16 +01:00
|
|
|
/* remove l2vni from l2vni's tenant-vrf l3-vni list */
|
|
|
|
zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (zl3vni)
|
2020-07-23 23:51:10 +02:00
|
|
|
listnode_delete(zl3vni->l2vnis, zevpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_cleanup_all(bucket, arg);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2017-11-14 08:12:15 +01:00
|
|
|
/* cleanup L3VNI */
|
2019-02-19 16:46:52 +01:00
|
|
|
static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args)
|
2017-11-14 08:12:15 +01:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-11-14 08:12:15 +01:00
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)bucket->data;
|
2017-11-14 08:12:15 +01:00
|
|
|
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
}
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
|
2019-11-08 20:13:33 +01:00
|
|
|
const struct prefix *host)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry lookup;
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
|
|
|
|
memset(&lookup, 0, sizeof(lookup));
|
|
|
|
memcpy(&lookup.p, host, sizeof(*host));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
2018-05-17 01:24:22 +02:00
|
|
|
if (hle)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry));
|
|
|
|
memcpy(hle, &lookup, sizeof(lookup));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_INSERT(host_rb_tree_entry, hrbe, hle);
|
2018-05-17 01:24:22 +02:00
|
|
|
}
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
|
2018-05-17 01:24:22 +02:00
|
|
|
{
|
|
|
|
struct host_rb_entry lookup;
|
|
|
|
struct host_rb_entry *hle;
|
|
|
|
|
|
|
|
memset(&lookup, 0, sizeof(lookup));
|
|
|
|
memcpy(&lookup.p, host, sizeof(*host));
|
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
2018-06-04 19:31:34 +02:00
|
|
|
if (hle) {
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_REMOVE(host_rb_tree_entry, hrbe, hle);
|
2018-06-04 19:31:34 +02:00
|
|
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
|
|
|
}
|
2018-05-17 01:24:22 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Look up MAC hash entry.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_mac *zl3vni_rmac_lookup(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
const struct ethaddr *rmac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac tmp;
|
|
|
|
struct zebra_mac *pmac;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.macaddr, rmac, ETH_ALEN);
|
|
|
|
pmac = hash_lookup(zl3vni->rmac_table, &tmp);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return pmac;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Callback to allocate RMAC hash entry.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2017-10-13 10:13:48 +02:00
|
|
|
static void *zl3vni_rmac_alloc(void *p)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
const struct zebra_mac *tmp_rmac = p;
|
|
|
|
struct zebra_mac *zrmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-19 22:33:53 +02:00
|
|
|
zrmac = XCALLOC(MTYPE_L3VNI_MAC, sizeof(struct zebra_mac));
|
2017-10-08 03:49:27 +02:00
|
|
|
*zrmac = *tmp_rmac;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return ((void *)zrmac);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Add RMAC entry to l3-vni
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_mac *zl3vni_rmac_add(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
const struct ethaddr *rmac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac tmp_rmac;
|
|
|
|
struct zebra_mac *zrmac = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_rmac, 0, sizeof(tmp_rmac));
|
2017-10-08 03:49:27 +02:00
|
|
|
memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN);
|
|
|
|
zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
|
2021-09-29 04:01:16 +02:00
|
|
|
zrmac->nh_list = list_new();
|
|
|
|
zrmac->nh_list->cmp = (int (*)(void *, void *))l3vni_rmac_nh_list_cmp;
|
|
|
|
zrmac->nh_list->del = (void (*)(void *))l3vni_rmac_nh_free;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE);
|
|
|
|
SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return zrmac;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Delete MAC entry.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *tmp_rmac;
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
/* free the list of nh list*/
|
|
|
|
list_delete(&zrmac->nh_list);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
|
2020-07-23 23:58:45 +02:00
|
|
|
XFREE(MTYPE_L3VNI_MAC, tmp_rmac);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
|
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Install remote RMAC into the forwarding plane.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_mac *zrmac)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif = NULL, *br_zif = NULL;
|
2021-07-27 09:44:15 +02:00
|
|
|
const struct zebra_vxlan_vni *vni;
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct interface *br_ifp;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2019-09-05 18:58:58 +02:00
|
|
|
vlanid_t vid;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
|| !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)br_ifp->info;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
2021-07-27 09:44:15 +02:00
|
|
|
vid = vni->access_vlan;
|
2019-09-05 18:58:58 +02:00
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
2021-07-27 09:52:11 +02:00
|
|
|
res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
|
|
|
|
vni->vni, zrmac->fwd_info.r_vtep_ip, 0, 0,
|
2020-03-28 18:16:30 +01:00
|
|
|
false /*was_static*/);
|
2019-07-30 17:54:07 +02:00
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2019-07-30 17:54:07 +02:00
|
|
|
* Uninstall remote RMAC from the forwarding plane.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_mac *zrmac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct zebra_if *zif = NULL, *br_zif;
|
2021-07-27 09:44:15 +02:00
|
|
|
const struct zebra_vxlan_vni *vni;
|
2019-09-05 18:58:58 +02:00
|
|
|
const struct interface *br_ifp;
|
|
|
|
vlanid_t vid;
|
2019-07-30 17:54:07 +02:00
|
|
|
enum zebra_dplane_result res;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE))
|
|
|
|
|| !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!zl3vni->vxlan_if) {
|
2019-09-05 17:05:03 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"RMAC %pEA on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
|
|
|
|
&zrmac->macaddr, zl3vni->vni, zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return -1;
|
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_ifp = zif->brslave_info.br_if;
|
|
|
|
if (br_ifp == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-09-05 18:58:58 +02:00
|
|
|
br_zif = (const struct zebra_if *)br_ifp->info;
|
|
|
|
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
|
2021-07-27 09:44:15 +02:00
|
|
|
vid = vni->access_vlan;
|
2019-09-05 18:58:58 +02:00
|
|
|
else
|
|
|
|
vid = 0;
|
|
|
|
|
2021-07-27 09:52:11 +02:00
|
|
|
res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
|
|
|
|
vni->vni, zrmac->fwd_info.r_vtep_ip);
|
2019-07-30 17:54:07 +02:00
|
|
|
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* handle rmac add */
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni,
|
2019-11-08 20:13:33 +01:00
|
|
|
const struct ethaddr *rmac,
|
2021-10-18 20:43:29 +02:00
|
|
|
const struct ipaddr *vtep_ip)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2021-09-29 04:01:16 +02:00
|
|
|
struct ipaddr *vtep = NULL;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* Create the RMAC entry, or update its vtep, if necessary. */
|
2017-10-13 10:13:48 +02:00
|
|
|
zrmac = zl3vni_rmac_add(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2021-10-18 20:43:29 +02:00
|
|
|
"Failed to add RMAC %pEA L3VNI %u Remote VTEP %pIA",
|
|
|
|
rmac, zl3vni->vni, vtep_ip);
|
2017-10-13 10:13:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
|
|
|
|
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
|
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr));
|
|
|
|
memcpy(vtep, vtep_ip, sizeof(struct ipaddr));
|
|
|
|
if (!listnode_add_sort_nodup(zrmac->nh_list, (void *)vtep))
|
|
|
|
XFREE(MTYPE_EVPN_VTEP, vtep);
|
|
|
|
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, false,
|
|
|
|
"new RMAC added");
|
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* install rmac in kernel */
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
} else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip,
|
|
|
|
&vtep_ip->ipaddr_v4)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-10-18 20:43:29 +02:00
|
|
|
"L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA",
|
2021-03-12 02:44:45 +01:00
|
|
|
zl3vni->vni, &zrmac->fwd_info.r_vtep_ip,
|
2021-10-18 20:43:29 +02:00
|
|
|
vtep_ip, rmac);
|
2019-10-28 21:47:05 +01:00
|
|
|
|
|
|
|
zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
|
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr));
|
|
|
|
memcpy(vtep, vtep_ip, sizeof(struct ipaddr));
|
|
|
|
if (!listnode_add_sort_nodup(zrmac->nh_list, (void *)vtep))
|
|
|
|
XFREE(MTYPE_EVPN_VTEP, vtep);
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* install rmac in kernel */
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
}
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* handle rmac delete */
|
2021-08-20 14:58:24 +02:00
|
|
|
static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni,
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac,
|
2021-10-18 20:43:29 +02:00
|
|
|
struct ipaddr *vtep_ip)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2021-09-29 04:01:16 +02:00
|
|
|
struct ipaddr ipv4_vtep;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-10-15 20:47:25 +02:00
|
|
|
if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&ipv4_vtep, 0, sizeof(ipv4_vtep));
|
2021-09-29 04:01:16 +02:00
|
|
|
ipv4_vtep.ipa_type = IPADDR_V4;
|
|
|
|
if (vtep_ip->ipa_type == IPADDR_V6)
|
|
|
|
ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
|
|
|
|
&ipv4_vtep.ipaddr_v4);
|
|
|
|
else
|
|
|
|
memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
|
|
|
|
sizeof(struct in_addr));
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
/* remove nh from rmac's list */
|
|
|
|
l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep);
|
|
|
|
/* delete nh is same as current selected, fall back to
|
|
|
|
* one present in the list
|
|
|
|
*/
|
|
|
|
if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip,
|
|
|
|
&ipv4_vtep.ipaddr_v4) &&
|
|
|
|
listcount(zrmac->nh_list)) {
|
|
|
|
struct ipaddr *vtep;
|
Zebra: Handle RMAC add/delete operation and add fpm_mac_info_t
- Define a hook "zebra_mac_update" which can be registered by multiple
data plane components (e.g. FPM, dplane).
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool
delete, const char *reason), (rmac, zl3vni, delete, reason))
- While performing RMAC add/delete for an L3VNI, call "zebra_mac_update" hook.
- This hook call triggers "zfpm_trigger_rmac_update". In this function, we do a
lookup for the RMAC in fpm_mac_info_table. If already present, this node is
updated with the latest RMAC info. Else, a new fpm_mac_info_t node is created
and inserted in the queue and hash data structures.
Signed-off-by: Ameya Dharkar <adharkar@vmware.com>
2019-05-16 23:43:41 +02:00
|
|
|
|
2021-09-29 04:01:16 +02:00
|
|
|
vtep = listgetdata(listhead(zrmac->nh_list));
|
|
|
|
zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4;
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-10-18 20:43:29 +02:00
|
|
|
"L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA",
|
2021-09-29 04:01:16 +02:00
|
|
|
zl3vni->vni, &ipv4_vtep,
|
|
|
|
&zrmac->fwd_info.r_vtep_ip,
|
2021-10-18 20:43:29 +02:00
|
|
|
&zrmac->macaddr);
|
2021-09-29 04:01:16 +02:00
|
|
|
|
|
|
|
/* install rmac in kernel */
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
}
|
2021-10-15 20:47:25 +02:00
|
|
|
|
|
|
|
if (!listcount(zrmac->nh_list)) {
|
|
|
|
/* uninstall from kernel */
|
|
|
|
zl3vni_rmac_uninstall(zl3vni, zrmac);
|
|
|
|
|
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, true,
|
|
|
|
"RMAC deleted");
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"L3VNI %u RMAC %pEA vtep_ip %pIA delete",
|
|
|
|
zl3vni->vni, &zrmac->macaddr, vtep_ip);
|
|
|
|
|
|
|
|
/* del the rmac entry */
|
|
|
|
zl3vni_rmac_del(zl3vni, zrmac);
|
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2021-04-01 18:00:04 +02:00
|
|
|
* Common code for look up of nh hash entry.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2021-04-01 18:00:04 +02:00
|
|
|
static struct zebra_neigh *_nh_lookup(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *ip)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh tmp;
|
|
|
|
struct zebra_neigh *n;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
|
2021-04-01 18:00:04 +02:00
|
|
|
|
|
|
|
if (zl3vni)
|
|
|
|
n = hash_lookup(zl3vni->nh_table, &tmp);
|
|
|
|
else
|
|
|
|
n = hash_lookup(svd_nh_table, &tmp);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return n;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/*
|
|
|
|
* Look up nh hash entry on a l3-vni.
|
|
|
|
*/
|
|
|
|
static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
return _nh_lookup(zl3vni, ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up nh hash entry on a SVD.
|
|
|
|
*/
|
|
|
|
static struct zebra_neigh *svd_nh_lookup(const struct ipaddr *ip)
|
|
|
|
{
|
|
|
|
return _nh_lookup(NULL, ip);
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate NH hash entry on L3-VNI.
|
|
|
|
*/
|
2017-10-13 10:13:48 +02:00
|
|
|
static void *zl3vni_nh_alloc(void *p)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
const struct zebra_neigh *tmp_n = p;
|
|
|
|
struct zebra_neigh *n;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-08-20 15:01:26 +02:00
|
|
|
n = XCALLOC(MTYPE_L3NEIGH, sizeof(struct zebra_neigh));
|
2017-10-08 03:49:27 +02:00
|
|
|
*n = *tmp_n;
|
|
|
|
|
|
|
|
return ((void *)n);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2021-04-01 18:00:04 +02:00
|
|
|
* Common code for neigh add.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2021-04-01 18:00:04 +02:00
|
|
|
static struct zebra_neigh *_nh_add(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *ip,
|
|
|
|
const struct ethaddr *mac)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh tmp_n;
|
|
|
|
struct zebra_neigh *n = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_n, 0, sizeof(tmp_n));
|
2017-10-08 03:49:27 +02:00
|
|
|
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
|
2021-04-01 18:00:04 +02:00
|
|
|
|
|
|
|
if (zl3vni)
|
|
|
|
n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
|
|
|
|
else
|
|
|
|
n = hash_get(svd_nh_table, &tmp_n, zl3vni_nh_alloc);
|
|
|
|
|
|
|
|
assert(n);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_INIT(host_rb_tree_entry, &n->host_rb);
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
memcpy(&n->emac, mac, ETH_ALEN);
|
2017-10-13 10:13:48 +02:00
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
|
|
|
|
SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE_NH);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return n;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/*
|
|
|
|
* Add neighbor entry.
|
|
|
|
*/
|
|
|
|
static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *ip,
|
|
|
|
const struct ethaddr *mac)
|
|
|
|
{
|
|
|
|
return _nh_add(zl3vni, ip, mac);
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Delete neighbor entry.
|
|
|
|
*/
|
2021-08-20 15:01:26 +02:00
|
|
|
static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *tmp_n;
|
2018-05-17 14:18:23 +02:00
|
|
|
struct host_rb_entry *hle;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
while (!RB_EMPTY(host_rb_tree_entry, &n->host_rb)) {
|
|
|
|
hle = RB_ROOT(host_rb_tree_entry, &n->host_rb);
|
2018-05-17 14:18:23 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
RB_REMOVE(host_rb_tree_entry, &n->host_rb, hle);
|
2018-05-17 14:18:23 +02:00
|
|
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
|
|
|
}
|
2017-10-17 02:41:04 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_n = hash_release(zl3vni->nh_table, n);
|
2020-07-24 00:30:23 +02:00
|
|
|
XFREE(MTYPE_L3NEIGH, tmp_n);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2021-04-01 18:00:04 +02:00
|
|
|
* Add Single VXlan Device neighbor entry.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2021-04-01 18:00:04 +02:00
|
|
|
static struct zebra_neigh *svd_nh_add(const struct ipaddr *ip,
|
|
|
|
const struct ethaddr *mac)
|
|
|
|
{
|
|
|
|
return _nh_add(NULL, ip, mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Del Single VXlan Device neighbor entry.
|
|
|
|
*/
|
|
|
|
static int svd_nh_del(struct zebra_neigh *n)
|
|
|
|
{
|
|
|
|
if (n->refcnt > 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
hash_release(svd_nh_table, n);
|
|
|
|
XFREE(MTYPE_L3NEIGH, n);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common code to install remote nh as neigh into the kernel.
|
|
|
|
*/
|
|
|
|
static int _nh_install(struct zebra_l3vni *zl3vni, struct interface *ifp,
|
|
|
|
struct zebra_neigh *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-07-07 06:46:46 +02:00
|
|
|
uint8_t flags;
|
|
|
|
int ret = 0;
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
if (zl3vni && !is_l3vni_oper_up(zl3vni))
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
|
|
|
|
return 0;
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
flags = DPLANE_NTF_EXT_LEARNED;
|
2018-07-07 06:46:46 +02:00
|
|
|
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
|
2019-08-23 19:59:10 +02:00
|
|
|
flags |= DPLANE_NTF_ROUTER;
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
dplane_rem_neigh_add(ifp, &n->ip, &n->emac, flags,
|
|
|
|
false /*was_static*/);
|
2019-08-23 19:59:10 +02:00
|
|
|
|
2018-07-07 06:46:46 +02:00
|
|
|
return ret;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/*
|
2021-04-01 18:00:04 +02:00
|
|
|
* Common code to uninstall remote nh from the kernel.
|
2017-10-08 03:49:27 +02:00
|
|
|
*/
|
2021-04-01 18:00:04 +02:00
|
|
|
static int _nh_uninstall(struct interface *ifp, struct zebra_neigh *n)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|
|
|
|
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
|
|
|
|
return 0;
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
if (!ifp || !if_is_operative(ifp))
|
2017-12-02 08:31:22 +01:00
|
|
|
return 0;
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
dplane_rem_neigh_delete(ifp, &n->ip);
|
2019-08-23 19:59:10 +02:00
|
|
|
|
|
|
|
return 0;
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/*
|
|
|
|
* Install remote nh as neigh into the kernel.
|
|
|
|
*/
|
|
|
|
static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
|
|
|
|
{
|
|
|
|
return _nh_install(zl3vni, zl3vni->svi_if, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall remote nh from the kernel.
|
|
|
|
*/
|
|
|
|
static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_neigh *n)
|
|
|
|
{
|
|
|
|
return _nh_uninstall(zl3vni->svi_if, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install SVD remote nh as neigh into the kernel.
|
|
|
|
*/
|
|
|
|
static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
|
|
|
|
{
|
|
|
|
return _nh_install(zl3vni, zl3vni->vxlan_if, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uninstall SVD remote nh from the kernel.
|
|
|
|
*/
|
|
|
|
static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
|
|
|
|
{
|
|
|
|
return _nh_uninstall(zl3vni->vxlan_if, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add remote vtep as a neigh entry */
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_remote_nh_add(struct zebra_l3vni *zl3vni,
|
2019-11-08 20:13:33 +01:00
|
|
|
const struct ipaddr *vtep_ip,
|
|
|
|
const struct ethaddr *rmac,
|
|
|
|
const struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *nh = NULL;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2019-10-28 21:47:05 +01:00
|
|
|
/* Create the next hop entry, or update its mac, if necessary. */
|
2017-10-13 10:13:48 +02:00
|
|
|
nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
|
|
|
|
if (!nh) {
|
|
|
|
nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac);
|
|
|
|
if (!nh) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Failed to add NH %pIA as Neigh (RMAC %pEA L3-VNI %u prefix %pFX)",
|
|
|
|
vtep_ip, rmac, zl3vni->vni, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* install the nh neigh in kernel */
|
|
|
|
zl3vni_nh_install(zl3vni, nh);
|
2019-10-28 21:47:05 +01:00
|
|
|
} else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"L3VNI %u RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX",
|
|
|
|
zl3vni->vni, &nh->emac, rmac, vtep_ip,
|
2020-10-18 13:33:54 +02:00
|
|
|
host_prefix);
|
2019-10-28 21:47:05 +01:00
|
|
|
|
|
|
|
memcpy(&nh->emac, rmac, ETH_ALEN);
|
|
|
|
/* install (update) the nh neigh in kernel */
|
|
|
|
zl3vni_nh_install(zl3vni, nh);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2018-05-17 14:18:23 +02:00
|
|
|
rb_find_or_add_host(&nh->host_rb, host_prefix);
|
2017-10-16 23:57:42 +02:00
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* Del remote vtep as a neigh entry */
|
2021-08-20 15:01:26 +02:00
|
|
|
static void zl3vni_remote_nh_del(struct zebra_l3vni *zl3vni,
|
|
|
|
struct zebra_neigh *nh,
|
2017-11-29 08:40:30 +01:00
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2018-05-17 14:18:23 +02:00
|
|
|
rb_delete_host(&nh->host_rb, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-05-21 13:18:18 +02:00
|
|
|
if (RB_EMPTY(host_rb_tree_entry, &nh->host_rb)) {
|
2017-10-13 10:13:48 +02:00
|
|
|
/* uninstall from kernel */
|
|
|
|
zl3vni_nh_uninstall(zl3vni, nh);
|
|
|
|
|
|
|
|
/* delete the nh entry */
|
|
|
|
zl3vni_nh_del(zl3vni, nh);
|
|
|
|
}
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* Add remote vtep as a SVD neigh entry */
|
|
|
|
static int svd_remote_nh_add(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *vtep_ip,
|
|
|
|
const struct ethaddr *rmac,
|
|
|
|
const struct prefix *host_prefix)
|
|
|
|
{
|
|
|
|
struct zebra_neigh *nh = NULL;
|
|
|
|
|
|
|
|
/* SVD backed VNI check */
|
|
|
|
if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Create the SVD next hop entry, or update its mac, if necessary. */
|
|
|
|
nh = svd_nh_lookup(vtep_ip);
|
|
|
|
if (!nh) {
|
|
|
|
nh = svd_nh_add(vtep_ip, rmac);
|
|
|
|
if (!nh) {
|
|
|
|
zlog_debug(
|
|
|
|
"Failed to add NH %pIA as SVD Neigh (RMAC %pEA prefix %pFX)",
|
|
|
|
vtep_ip, rmac, host_prefix);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"SVD RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX",
|
|
|
|
&nh->emac, rmac, vtep_ip, host_prefix);
|
|
|
|
|
|
|
|
memcpy(&nh->emac, rmac, ETH_ALEN);
|
|
|
|
/* install (update) the nh neigh in kernel */
|
|
|
|
svd_nh_install(zl3vni, nh);
|
|
|
|
|
|
|
|
/* Don't increment refcnt change */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
nh->refcnt++;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("SVD NH ADD refcnt (%u) for nexthop %pIA",
|
|
|
|
nh->refcnt, vtep_ip);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install the nh neigh in kernel if this is the first time we
|
|
|
|
* have seen it.
|
|
|
|
*/
|
|
|
|
if (nh->refcnt == 1)
|
|
|
|
svd_nh_install(zl3vni, nh);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Del remote vtep as a SVD neigh entry */
|
|
|
|
static int svd_remote_nh_del(struct zebra_l3vni *zl3vni,
|
|
|
|
const struct ipaddr *vtep_ip)
|
|
|
|
{
|
|
|
|
struct zebra_neigh *nh;
|
|
|
|
|
|
|
|
/* SVD backed VNI check */
|
|
|
|
if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nh = svd_nh_lookup(vtep_ip);
|
|
|
|
if (!nh) {
|
|
|
|
zlog_debug("Failed to del NH %pIA as SVD Neigh", vtep_ip);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nh->refcnt--;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("SVD NH Del refcnt (%u) for nexthop %pIA",
|
|
|
|
nh->refcnt, vtep_ip);
|
|
|
|
|
|
|
|
/* Last refcnt on NH, remove it completely. */
|
|
|
|
if (nh->refcnt == 0) {
|
|
|
|
svd_nh_uninstall(zl3vni, nh);
|
|
|
|
svd_nh_del(nh);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-09 18:13:28 +01:00
|
|
|
/* handle neigh update from kernel - the only thing of interest is to
|
|
|
|
* readd stale entries.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_local_nh_add_update(struct zebra_l3vni *zl3vni,
|
|
|
|
struct ipaddr *ip, uint16_t state)
|
2017-11-09 18:13:28 +01:00
|
|
|
{
|
2017-12-14 00:04:44 +01:00
|
|
|
#ifdef GNU_LINUX
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n = NULL;
|
2017-11-09 18:13:28 +01:00
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* all next hop neigh are remote and installed by frr.
|
|
|
|
* If the kernel has aged this entry, re-install.
|
|
|
|
*/
|
|
|
|
if (state & NUD_STALE)
|
|
|
|
zl3vni_nh_install(zl3vni, n);
|
2017-12-14 00:04:44 +01:00
|
|
|
#endif
|
2017-11-09 18:13:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-22 10:16:54 +02:00
|
|
|
/* handle neigh delete from kernel */
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_local_nh_del(struct zebra_l3vni *zl3vni, struct ipaddr *ip)
|
2017-10-22 10:16:54 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n = NULL;
|
2017-10-22 10:16:54 +02:00
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* all next hop neigh are remote and installed by frr.
|
|
|
|
* If we get an age out notification for these neigh entries, we have to
|
2017-12-27 20:47:10 +01:00
|
|
|
* install it back
|
|
|
|
*/
|
2017-10-22 10:16:54 +02:00
|
|
|
zl3vni_nh_install(zl3vni, n);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Hash function for L3 VNI.
|
|
|
|
*/
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int l3vni_hash_keymake(const void *p)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
const struct zebra_l3vni *zl3vni = p;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return jhash_1word(zl3vni->vni, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare 2 L3 VNI hash entries.
|
|
|
|
*/
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool l3vni_hash_cmp(const void *p1, const void *p2)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
const struct zebra_l3vni *zl3vni1 = p1;
|
|
|
|
const struct zebra_l3vni *zl3vni2 = p2;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return (zl3vni1->vni == zl3vni2->vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to allocate L3 VNI hash entry.
|
|
|
|
*/
|
|
|
|
static void *zl3vni_alloc(void *p)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
const struct zebra_l3vni *tmp_l3vni = p;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(struct zebra_l3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vni = tmp_l3vni->vni;
|
|
|
|
return ((void *)zl3vni);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up L3 VNI hash entry.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni_lookup(vni_t vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni tmp_l3vni;
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_l3vni, 0, sizeof(tmp_l3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_l3vni.vni = vni;
|
2018-08-27 16:43:37 +02:00
|
|
|
zl3vni = hash_lookup(zrouter.l3vni_table, &tmp_l3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add L3 VNI hash entry.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_l3vni *zl3vni_add(vni_t vni, vrf_id_t vrf_id)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni tmp_zl3vni;
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&tmp_zl3vni, 0, sizeof(tmp_zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
tmp_zl3vni.vni = vni;
|
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
zl3vni = hash_get(zrouter.l3vni_table, &tmp_zl3vni, zl3vni_alloc);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zl3vni->vrf_id = vrf_id;
|
|
|
|
zl3vni->svi_if = NULL;
|
|
|
|
zl3vni->vxlan_if = NULL;
|
|
|
|
zl3vni->l2vnis = list_new();
|
2020-08-10 18:40:48 +02:00
|
|
|
zl3vni->l2vnis->cmp = zebra_evpn_list_cmp;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Create hash table for remote RMAC */
|
2020-07-23 23:58:45 +02:00
|
|
|
zl3vni->rmac_table = zebra_mac_db_create("Zebra L3-VNI RMAC-Table");
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Create hash table for neighbors */
|
2020-07-24 00:30:23 +02:00
|
|
|
zl3vni->nh_table = zebra_neigh_db_create("Zebra L3-VNI next-hop table");
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete L3 VNI hash entry.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_del(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *tmp_zl3vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* free the list of l2vnis */
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&zl3vni->l2vnis);
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->l2vnis = NULL;
|
|
|
|
|
|
|
|
/* Free the rmac table */
|
|
|
|
hash_free(zl3vni->rmac_table);
|
|
|
|
zl3vni->rmac_table = NULL;
|
|
|
|
|
|
|
|
/* Free the nh table */
|
|
|
|
hash_free(zl3vni->nh_table);
|
|
|
|
zl3vni->nh_table = NULL;
|
|
|
|
|
|
|
|
/* Free the VNI hash entry and allocated memory. */
|
2018-08-27 16:43:37 +02:00
|
|
|
tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
|
|
|
|
void *_zl3vni,
|
|
|
|
void **_pifp)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2019-12-20 17:51:37 +01:00
|
|
|
struct zebra_ns *zns = ns->info;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = (struct zebra_l3vni *)_zl3vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct interface *ifp = NULL;
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_get_evpn();
|
|
|
|
|
2022-03-30 09:18:33 +02:00
|
|
|
assert(_pifp);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* loop through all vxlan-interface */
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
|
|
|
|
struct zebra_if *zif = NULL;
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct zebra_vxlan_vni *vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
2021-07-27 09:44:15 +02:00
|
|
|
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
2021-08-07 19:01:36 +02:00
|
|
|
if (!vni || vni->vni != zl3vni->vni)
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
|
|
|
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Intf %s(%u) VNI %u, link not in same "
|
|
|
|
"namespace than BGP EVPN core instance ",
|
2021-07-27 09:44:15 +02:00
|
|
|
ifp->name, ifp->ifindex, vni->vni);
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
continue;
|
2017-10-31 00:58:15 +01:00
|
|
|
}
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
|
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
|
2022-03-30 09:18:33 +02:00
|
|
|
*_pifp = (void *)ifp;
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_STOP;
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_CONTINUE;
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni)
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
{
|
|
|
|
struct interface **p_ifp;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
|
|
|
|
p_ifp = &ifp;
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
ns_walk_func(zl3vni_map_to_vxlan_if_ns,
|
|
|
|
(void *)zl3vni, (void **)p_ifp);
|
zebra: importation of bgp evpn rt5 from vni with other netns
With vrf-lite mechanisms, it is possible to create layer 3 vnis by
creating a bridge interface in default vr, by creating a vxlan interface
that is attached to that bridge interface, then by moving the vxlan
interface to the wished vrf.
With vrf-netns mechanism, it is slightly different since bridged
interfaces can not be separated in different network namespaces. To make
it work, the setup consists in :
- creating a vxlan interface on default vrf.
- move the vxlan interface to the wished vrf ( with an other netns)
- create a bridge interface in the wished vrf
- attach the vxlan interface to that bridged interface
from that point, if BGP is enabled to advertise vnis in default vrf,
then vxlan interfaces are discovered appropriately in other vrfs,
provided that the link interface still resides in the vrf where l2vpn is
advertised.
to import ipv4 entries from a separate vrf, into the l2vpn, the
configuration of vni in the dedicated vrf + the advertisement of ipv4
entries in bgp vrf will import the entries in the bgp l2vpn.
the modification consists in parsing the vxlan interfaces in all network
namespaces, where the link resides in the same network namespace as the
bgp core instance where bgp l2vpn is enabled.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2019-09-26 18:49:59 +02:00
|
|
|
return ifp;
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_vxlan_vni *vni = NULL; /* vni info in vxlan_if */
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!zl3vni->vxlan_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return NULL;
|
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
|
|
|
if (!vni)
|
|
|
|
return NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
return zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
struct interface *zl3vni_map_to_mac_vlan_if(struct zebra_l3vni *zl3vni)
|
2019-08-02 08:33:24 +02:00
|
|
|
{
|
|
|
|
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
|
|
|
|
|
|
|
|
if (!zl3vni)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!zl3vni->vxlan_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = zl3vni->vxlan_if->info;
|
|
|
|
if (!zif)
|
|
|
|
return NULL;
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
return zebra_evpn_map_to_macvlan(zif->brslave_info.br_if,
|
|
|
|
zl3vni->svi_if);
|
2019-08-02 08:33:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(vrf_id);
|
|
|
|
if (!zvrf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return zl3vni_lookup(zvrf->l3vni);
|
|
|
|
}
|
|
|
|
|
2021-08-17 10:31:13 +02:00
|
|
|
static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
|
|
|
|
{
|
2021-07-27 11:24:40 +02:00
|
|
|
int found = 0;
|
|
|
|
vni_t vni_id = 0;
|
2021-08-17 10:31:13 +02:00
|
|
|
struct zebra_ns *zns = ns->info;
|
|
|
|
struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
|
|
|
|
struct zebra_from_svi_param *in_param =
|
|
|
|
(struct zebra_from_svi_param *)_in_param;
|
|
|
|
struct route_node *rn = NULL;
|
|
|
|
struct interface *tmp_if = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
2021-07-27 11:24:40 +02:00
|
|
|
struct zebra_if *br_zif = NULL;
|
2021-08-17 10:31:13 +02:00
|
|
|
|
2022-03-30 09:18:33 +02:00
|
|
|
assert(in_param && p_zl3vni);
|
2021-08-17 10:31:13 +02:00
|
|
|
|
2021-07-27 11:24:40 +02:00
|
|
|
br_zif = in_param->br_if->info;
|
|
|
|
assert(br_zif);
|
2021-08-17 10:31:13 +02:00
|
|
|
|
2021-07-27 11:24:40 +02:00
|
|
|
if (in_param->bridge_vlan_aware) {
|
|
|
|
vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid);
|
|
|
|
if (vni_id)
|
|
|
|
found = 1;
|
|
|
|
} else {
|
|
|
|
/* loop through all vxlan-interface */
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
tmp_if = (struct interface *)rn->info;
|
|
|
|
if (!tmp_if)
|
|
|
|
continue;
|
|
|
|
zif = tmp_if->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
if (!if_is_operative(tmp_if))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (zif->brslave_info.br_if != in_param->br_if)
|
|
|
|
continue;
|
|
|
|
|
2021-07-27 18:20:47 +02:00
|
|
|
vni_id = zebra_vxlan_if_access_vlan_vni_find(
|
2022-12-10 00:51:22 +01:00
|
|
|
zif, in_param->br_if);
|
2021-07-27 11:24:40 +02:00
|
|
|
if (vni_id) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
2021-08-17 10:31:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-27 11:24:40 +02:00
|
|
|
if (!found)
|
|
|
|
return NS_WALK_CONTINUE;
|
|
|
|
|
|
|
|
*p_zl3vni = zl3vni_lookup(vni_id);
|
|
|
|
return NS_WALK_STOP;
|
2021-08-17 10:31:13 +02:00
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Map SVI and associated bridge to a VNI. This is invoked upon getting
|
|
|
|
* neighbor notifications, to see if they are of interest.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
|
|
|
|
struct interface *br_if)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_if *zif = NULL;
|
2021-08-17 10:31:13 +02:00
|
|
|
struct zebra_from_svi_param in_param = {};
|
|
|
|
struct zebra_l3vni **p_zl3vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!br_if)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Make sure the linked interface is a bridge. */
|
|
|
|
if (!IS_ZEBRA_IF_BRIDGE(br_if))
|
|
|
|
return NULL;
|
2021-08-17 10:31:13 +02:00
|
|
|
in_param.br_if = br_if;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Determine if bridge is VLAN-aware or not */
|
|
|
|
zif = br_if->info;
|
|
|
|
assert(zif);
|
2021-07-27 09:47:52 +02:00
|
|
|
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
|
2021-08-17 10:31:13 +02:00
|
|
|
if (in_param.bridge_vlan_aware) {
|
2017-10-08 03:49:27 +02:00
|
|
|
struct zebra_l2info_vlan *vl;
|
|
|
|
|
|
|
|
if (!IS_ZEBRA_IF_VLAN(ifp))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
vl = &zif->l2info.vl;
|
2021-08-17 10:31:13 +02:00
|
|
|
in_param.vid = vl->vid;
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
|
|
|
/* TODO: Optimize with a hash. */
|
|
|
|
|
2021-08-17 10:31:13 +02:00
|
|
|
p_zl3vni = &zl3vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-08-17 10:31:13 +02:00
|
|
|
ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
return zl3vni;
|
|
|
|
}
|
|
|
|
|
2021-01-11 20:08:43 +01:00
|
|
|
vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if)
|
|
|
|
{
|
|
|
|
vni_t vni = 0;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-01-11 20:08:43 +01:00
|
|
|
|
|
|
|
/* Check if an L3VNI belongs to this SVI interface.
|
|
|
|
* If not, check if an L2VNI belongs to this SVI interface.
|
|
|
|
*/
|
|
|
|
zl3vni = zl3vni_from_svi(ifp, br_if);
|
|
|
|
if (zl3vni)
|
|
|
|
vni = zl3vni->vni;
|
|
|
|
else {
|
|
|
|
zevpn = zebra_evpn_from_svi(ifp, br_if);
|
|
|
|
if (zevpn)
|
|
|
|
vni = zevpn->vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vni;
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:58:24 +02:00
|
|
|
static inline void zl3vni_get_vrr_rmac(struct zebra_l3vni *zl3vni,
|
2019-08-02 08:33:24 +02:00
|
|
|
struct ethaddr *rmac)
|
|
|
|
{
|
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!is_l3vni_oper_up(zl3vni))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (zl3vni->mac_vlan_if && if_is_operative(zl3vni->mac_vlan_if))
|
|
|
|
memcpy(rmac->octet, zl3vni->mac_vlan_if->hw_addr, ETH_ALEN);
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Inform BGP about l3-vni.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_send_add_to_client(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct stream *s = NULL;
|
|
|
|
struct zserv *client = NULL;
|
2019-08-02 08:33:24 +02:00
|
|
|
struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} };
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
bool is_anycast_mac = true;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-10-08 03:49:27 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
zvrf = zebra_vrf_lookup_by_id(zl3vni->vrf_id);
|
|
|
|
assert(zvrf);
|
|
|
|
|
|
|
|
/* get the svi and vrr rmac values */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&svi_rmac, 0, sizeof(svi_rmac));
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni_get_svi_rmac(zl3vni, &svi_rmac);
|
|
|
|
zl3vni_get_vrr_rmac(zl3vni, &vrr_rmac);
|
|
|
|
|
|
|
|
/* In absence of vrr mac use svi mac as anycast MAC value */
|
|
|
|
if (is_zero_mac(&vrr_rmac)) {
|
|
|
|
memcpy(&vrr_rmac, &svi_rmac, ETH_ALEN);
|
|
|
|
is_anycast_mac = false;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
/* The message is used for both vni add and/or update like
|
|
|
|
* vrr mac is added for l3vni SVI.
|
|
|
|
*/
|
2018-01-22 14:16:27 +01:00
|
|
|
zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
stream_putl(s, zl3vni->vni);
|
2019-08-02 08:33:24 +02:00
|
|
|
stream_put(s, &svi_rmac, sizeof(struct ethaddr));
|
2017-10-31 00:58:15 +01:00
|
|
|
stream_put_in_addr(s, &zl3vni->local_vtep_ip);
|
2018-02-06 23:28:22 +01:00
|
|
|
stream_put(s, &zl3vni->filter, sizeof(int));
|
2019-02-27 12:52:34 +01:00
|
|
|
stream_putl(s, zl3vni->svi_if->ifindex);
|
2019-08-02 08:33:24 +02:00
|
|
|
stream_put(s, &vrr_rmac, sizeof(struct ethaddr));
|
|
|
|
stream_putl(s, is_anycast_mac);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-02-06 23:28:22 +01:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Send L3_VNI_ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s",
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
|
2021-03-12 02:44:45 +01:00
|
|
|
&svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip,
|
2018-02-06 23:28:22 +01:00
|
|
|
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
|
|
|
|
? "prefix-routes-only"
|
|
|
|
: "none",
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
client->l3vniadd_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inform BGP about local l3-VNI deletion.
|
|
|
|
*/
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
struct stream *s = NULL;
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
|
2018-04-24 00:35:35 +02:00
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
|
2017-10-08 03:49:27 +02:00
|
|
|
/* BGP may not be running. */
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2018-01-22 14:16:27 +01:00
|
|
|
zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni));
|
2017-10-08 03:49:27 +02:00
|
|
|
stream_putl(s, zl3vni->vni);
|
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni,
|
|
|
|
vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
client->l3vnidel_cnt++;
|
2018-04-24 00:35:35 +02:00
|
|
|
return zserv_send_message(client, s);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2021-07-27 09:47:52 +02:00
|
|
|
void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* send l3vni add to BGP */
|
|
|
|
zl3vni_send_add_to_client(zl3vni);
|
|
|
|
}
|
|
|
|
|
2021-07-27 09:47:52 +02:00
|
|
|
void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-02-05 22:51:45 +01:00
|
|
|
if (!zl3vni)
|
|
|
|
return;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* send l3-vni del to BGP*/
|
|
|
|
zl3vni_send_del_to_client(zl3vni);
|
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
|
2020-03-29 17:43:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = (struct zebra_evpn *)bucket->data;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = (struct zebra_l3vni *)ctxt;
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
if (zevpn->vrf_id == zl3vni_vrf_id(zl3vni))
|
|
|
|
listnode_add_sort(zl3vni->l2vnis, zevpn);
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/*
|
2020-12-02 04:54:53 +01:00
|
|
|
* Handle transition of vni from l2 to l3 and vice versa.
|
|
|
|
* This function handles only the L2VNI add/delete part of
|
|
|
|
* the above transition.
|
|
|
|
* L3VNI add/delete is handled by the calling functions.
|
2020-07-24 00:30:23 +02:00
|
|
|
*/
|
|
|
|
static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
|
|
|
|
int add)
|
2020-03-29 17:43:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2022-08-26 12:53:03 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* There is a possibility that VNI notification was already received
|
|
|
|
* from kernel and we programmed it as L2-VNI
|
|
|
|
* In such a case we need to delete this L2-VNI first, so
|
|
|
|
* that it can be reprogrammed as L3-VNI in the system. It is also
|
|
|
|
* possible that the vrf-vni mapping is removed from FRR while the vxlan
|
|
|
|
* interface is still present in kernel. In this case to keep it
|
|
|
|
* symmetric, we will delete the l3-vni and reprogram it as l2-vni
|
|
|
|
*/
|
|
|
|
if (add) {
|
|
|
|
/* Locate hash entry */
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-24 00:30:23 +02:00
|
|
|
if (!zevpn)
|
|
|
|
return 0;
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* Delete EVPN from BGP. */
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_send_del_to_client(zevpn);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH);
|
|
|
|
zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* Free up all remote VTEPs, if any. */
|
2022-05-16 15:18:26 +02:00
|
|
|
zebra_evpn_vtep_del_all(zevpn, 1);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2022-08-26 12:53:03 +02:00
|
|
|
zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_delete(zl3vni->l2vnis, zevpn);
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* Delete the hash entry. */
|
2020-08-10 18:40:48 +02:00
|
|
|
if (zebra_evpn_vxlan_del(zevpn)) {
|
2020-07-24 00:30:23 +02:00
|
|
|
flog_err(EC_ZEBRA_VNI_DEL_FAILED,
|
|
|
|
"Failed to del EVPN hash %p, VNI %u", zevpn,
|
|
|
|
zevpn->vni);
|
|
|
|
return -1;
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
2020-07-24 00:30:23 +02:00
|
|
|
} else {
|
2020-12-02 04:54:53 +01:00
|
|
|
struct zebra_ns *zns;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_vxlan_vni *vnip;
|
2020-12-02 04:54:53 +01:00
|
|
|
struct zebra_l2info_vxlan *vxl;
|
|
|
|
struct interface *vlan_if;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("Adding L2-VNI %u - transition from L3-VNI",
|
|
|
|
vni);
|
|
|
|
|
|
|
|
/* Find VxLAN interface for this VNI. */
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
|
|
|
ifp = (struct interface *)rn->info;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
|
|
|
zif = ifp->info;
|
|
|
|
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vxl = &zif->l2info.vxl;
|
2021-07-27 09:44:15 +02:00
|
|
|
vnip = zebra_vxlan_if_vni_find(zif, vni);
|
|
|
|
if (vnip) {
|
2020-12-02 04:54:53 +01:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_err(
|
|
|
|
"Adding L2-VNI - Failed to find VxLAN interface for VNI %u",
|
|
|
|
vni);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create VNI hash entry for L2VNI */
|
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
|
|
|
if (zevpn)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zevpn = zebra_evpn_add(vni);
|
|
|
|
|
|
|
|
/* Find bridge interface for the VNI */
|
2021-07-27 09:44:15 +02:00
|
|
|
vlan_if = zvni_map_to_svi(vnip->access_vlan,
|
2020-12-02 04:54:53 +01:00
|
|
|
zif->brslave_info.br_if);
|
2022-08-26 12:53:03 +02:00
|
|
|
if (vlan_if) {
|
2021-10-22 00:17:40 +02:00
|
|
|
zevpn->vrf_id = vlan_if->vrf->vrf_id;
|
2022-08-26 12:53:03 +02:00
|
|
|
zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
|
|
|
|
}
|
2020-12-02 04:54:53 +01:00
|
|
|
|
|
|
|
zevpn->vxlan_if = ifp;
|
|
|
|
zevpn->local_vtep_ip = vxl->vtep_ip;
|
|
|
|
|
|
|
|
/* Inform BGP if the VNI is up and mapped to a bridge. */
|
|
|
|
if (if_is_operative(ifp) && zif->brslave_info.br_if) {
|
|
|
|
zebra_evpn_send_add_to_client(zevpn);
|
|
|
|
zebra_evpn_read_mac_neigh(zevpn, ifp);
|
|
|
|
}
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
return 0;
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* delete and uninstall rmac hash entry */
|
|
|
|
static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx)
|
2020-03-29 17:43:55 +02:00
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2021-08-19 22:33:53 +02:00
|
|
|
zrmac = (struct zebra_mac *)bucket->data;
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)ctx;
|
2020-07-24 00:30:23 +02:00
|
|
|
zl3vni_rmac_uninstall(zl3vni, zrmac);
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* Send RMAC for FPM processing */
|
|
|
|
hook_call(zebra_rmac_update, zrmac, zl3vni, true, "RMAC deleted");
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
zl3vni_rmac_del(zl3vni, zrmac);
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* delete and uninstall nh hash entry */
|
|
|
|
static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx)
|
2020-03-29 17:43:55 +02:00
|
|
|
{
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2021-08-20 15:01:26 +02:00
|
|
|
n = (struct zebra_neigh *)bucket->data;
|
2021-08-20 14:58:24 +02:00
|
|
|
zl3vni = (struct zebra_l3vni *)ctx;
|
2020-07-24 00:30:23 +02:00
|
|
|
zl3vni_nh_uninstall(zl3vni, n);
|
|
|
|
zl3vni_nh_del(zl3vni, n);
|
|
|
|
}
|
2020-03-29 17:43:55 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
/* re-add remote rmac if needed */
|
2021-08-20 14:58:24 +02:00
|
|
|
static int zebra_vxlan_readd_remote_rmac(struct zebra_l3vni *zl3vni,
|
2020-07-24 00:30:23 +02:00
|
|
|
struct ethaddr *rmac)
|
|
|
|
{
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2020-07-24 00:30:23 +02:00
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2021-03-12 02:44:45 +01:00
|
|
|
zlog_debug("Del remote RMAC %pEA L3VNI %u - readd",
|
|
|
|
rmac, zl3vni->vni);
|
2020-07-24 00:30:23 +02:00
|
|
|
|
|
|
|
zl3vni_rmac_install(zl3vni, zrmac);
|
|
|
|
return 0;
|
2020-03-29 17:43:55 +02:00
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* Public functions */
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
int is_l3vni_for_prefix_routes_only(vni_t vni)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2018-02-06 23:28:22 +01:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* handle evpn route in vrf table */
|
2019-11-08 20:13:33 +01:00
|
|
|
void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
|
|
|
|
const struct ipaddr *vtep_ip,
|
|
|
|
const struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2018-04-09 06:04:11 +02:00
|
|
|
struct ipaddr ipv4_vtep;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return;
|
|
|
|
|
2018-04-29 20:35:39 +02:00
|
|
|
/*
|
2018-04-09 06:04:11 +02:00
|
|
|
* add the next hop neighbor -
|
|
|
|
* neigh to be installed is the ipv6 nexthop neigh
|
|
|
|
*/
|
2018-04-29 20:35:39 +02:00
|
|
|
zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* Add SVD next hop neighbor */
|
|
|
|
svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
|
|
|
|
|
2018-04-09 06:04:11 +02:00
|
|
|
/*
|
|
|
|
* if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
|
|
|
|
* address. Rmac is programmed against the ipv4 vtep because we only
|
|
|
|
* support ipv4 tunnels in the h/w right now
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&ipv4_vtep, 0, sizeof(ipv4_vtep));
|
2018-04-09 06:04:11 +02:00
|
|
|
ipv4_vtep.ipa_type = IPADDR_V4;
|
|
|
|
if (vtep_ip->ipa_type == IPADDR_V6)
|
|
|
|
ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6,
|
|
|
|
&(ipv4_vtep.ipaddr_v4));
|
|
|
|
else
|
|
|
|
memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4,
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
|
2018-04-29 20:35:39 +02:00
|
|
|
/*
|
|
|
|
* add the rmac - remote rmac to be installed is against the ipv4
|
2018-04-09 06:04:11 +02:00
|
|
|
* nexthop address
|
|
|
|
*/
|
2021-10-18 20:43:29 +02:00
|
|
|
zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* handle evpn vrf route delete */
|
2017-11-29 08:40:30 +01:00
|
|
|
void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
|
2017-10-16 23:57:42 +02:00
|
|
|
struct ipaddr *vtep_ip,
|
|
|
|
struct prefix *host_prefix)
|
2017-10-13 10:13:48 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *nh = NULL;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2017-10-13 10:13:48 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
2017-10-18 10:46:40 +02:00
|
|
|
if (!zl3vni)
|
2017-10-13 10:13:48 +02:00
|
|
|
return;
|
|
|
|
|
2017-11-29 08:40:30 +01:00
|
|
|
/* find the next hop entry and rmac entry */
|
|
|
|
nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
|
|
|
|
if (!nh)
|
|
|
|
return;
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac);
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* delete the next hop entry */
|
2017-11-29 08:40:30 +01:00
|
|
|
zl3vni_remote_nh_del(zl3vni, nh, host_prefix);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* Delete SVD next hop entry */
|
|
|
|
svd_remote_nh_del(zl3vni, vtep_ip);
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
/* delete the rmac entry */
|
2017-11-29 08:40:30 +01:00
|
|
|
if (zrmac)
|
2021-10-18 20:43:29 +02:00
|
|
|
zl3vni_remote_rmac_del(zl3vni, zrmac, vtep_ip);
|
2017-10-13 10:13:48 +02:00
|
|
|
}
|
|
|
|
|
2017-10-17 01:51:32 +02:00
|
|
|
void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ethaddr *rmac, bool use_json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *zrmac = NULL;
|
2017-10-17 14:25:47 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
2017-10-17 14:25:47 +02:00
|
|
|
}
|
|
|
|
|
2017-10-17 01:51:32 +02:00
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
2017-10-17 14:25:47 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-17 14:25:47 +02:00
|
|
|
else
|
2018-10-25 20:06:59 +02:00
|
|
|
vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
|
|
|
|
if (!zrmac) {
|
2017-10-17 14:25:47 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-17 14:25:47 +02:00
|
|
|
else
|
|
|
|
vty_out(vty,
|
2021-09-29 04:01:16 +02:00
|
|
|
"%% Requested RMAC doesn't exist in L3-VNI %u\n",
|
2017-10-17 14:25:47 +02:00
|
|
|
l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 14:25:47 +02:00
|
|
|
zl3vni_print_rmac(zrmac, vty, json);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_rmacs;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct rmac_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
num_rmacs = hashcount(zl3vni->rmac_table);
|
|
|
|
if (!num_rmacs)
|
|
|
|
return;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2017-10-08 03:49:27 +02:00
|
|
|
wctx.vty = vty;
|
2017-10-17 14:14:33 +02:00
|
|
|
wctx.json = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty, "Number of Remote RMACs known for this VNI: %u\n",
|
|
|
|
num_rmacs);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numRmacs", num_rmacs);
|
|
|
|
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
2017-10-17 13:59:42 +02:00
|
|
|
void *args[2];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 13:59:42 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-17 13:59:42 +02:00
|
|
|
void *))zl3vni_print_rmac_hash_all_vni,
|
|
|
|
args);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2017-10-17 01:51:32 +02:00
|
|
|
void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ipaddr *ip, bool use_json)
|
2017-10-17 01:51:32 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n = NULL;
|
2017-10-17 13:32:31 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 01:51:32 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
2017-10-17 13:32:31 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
/* If vni=0 passed, assume svd lookup */
|
|
|
|
if (!l3vni)
|
|
|
|
n = svd_nh_lookup(ip);
|
|
|
|
else {
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n",
|
|
|
|
l3vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = zl3vni_nh_lookup(zl3vni, ip);
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!n) {
|
2017-10-17 13:32:31 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty,
|
2021-04-08 20:27:57 +02:00
|
|
|
"%% Requested next-hop not present for L3-VNI %u\n",
|
2017-10-17 13:32:31 +02:00
|
|
|
l3vni);
|
2017-10-17 01:51:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 13:32:31 +02:00
|
|
|
zl3vni_print_nh(n, vty, json);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-17 01:51:32 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
static void l3vni_print_nh_table(struct hash *nh_table, struct vty *vty,
|
|
|
|
bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_nh;
|
2017-10-13 10:13:48 +02:00
|
|
|
struct nh_walk_ctx wctx;
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
num_nh = hashcount(nh_table);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!num_nh)
|
|
|
|
return;
|
|
|
|
|
2017-10-17 13:12:51 +02:00
|
|
|
if (use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
wctx.vty = vty;
|
2017-10-17 13:12:51 +02:00
|
|
|
wctx.json = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty, "Number of NH Neighbors known for this VNI: %u\n",
|
|
|
|
num_nh);
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json, "numNextHops", num_nh);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 20:27:57 +02:00
|
|
|
void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
|
|
|
|
{
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(l3vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l3vni_print_nh_table(zl3vni->nh_table, vty, use_json);
|
|
|
|
}
|
|
|
|
|
|
|
|
void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json)
|
|
|
|
{
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l3vni_print_nh_table(svd_nh_table, vty, use_json);
|
|
|
|
}
|
|
|
|
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2017-10-13 10:13:48 +02:00
|
|
|
json_object *json = NULL;
|
2017-10-17 12:48:06 +02:00
|
|
|
void *args[2];
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-13 10:13:48 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-13 10:13:48 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 12:48:06 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2017-10-17 12:48:06 +02:00
|
|
|
void *))zl3vni_print_nh_hash_all_vni,
|
|
|
|
args);
|
2017-10-13 10:13:48 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display L3 VNI information (VTY command handler).
|
|
|
|
*/
|
2018-08-29 14:19:54 +02:00
|
|
|
void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
void *args[2];
|
|
|
|
json_object *json = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-10-17 12:14:14 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
2017-10-17 12:14:14 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni) {
|
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-17 12:14:14 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_print(zl3vni, (void *)args);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
json_object *json_vrfs)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2017-11-15 10:01:00 +01:00
|
|
|
char buf[ETHER_ADDR_STRLEN];
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
if (!json_vrfs) {
|
|
|
|
vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n",
|
|
|
|
zvrf_name(zvrf), zl3vni->vni,
|
|
|
|
zl3vni_vxlan_if_name(zl3vni),
|
|
|
|
zl3vni_svi_if_name(zl3vni), zl3vni_state2str(zl3vni),
|
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
2017-10-08 03:49:27 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object *json_vrf = NULL;
|
2018-08-20 23:31:30 +02:00
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
json_vrf = json_object_new_object();
|
|
|
|
json_object_string_add(json_vrf, "vrf", zvrf_name(zvrf));
|
|
|
|
json_object_int_add(json_vrf, "vni", zl3vni->vni);
|
|
|
|
json_object_string_add(json_vrf, "vxlanIntf",
|
|
|
|
zl3vni_vxlan_if_name(zl3vni));
|
|
|
|
json_object_string_add(json_vrf, "sviIntf",
|
|
|
|
zl3vni_svi_if_name(zl3vni));
|
|
|
|
json_object_string_add(json_vrf, "state",
|
|
|
|
zl3vni_state2str(zl3vni));
|
|
|
|
json_object_string_add(
|
|
|
|
json_vrf, "routerMac",
|
|
|
|
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
|
|
|
|
json_object_array_add(json_vrfs, json_vrf);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display Neighbors for a VNI (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
vni_t vni, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-10-08 03:49:27 +02:00
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2017-10-08 03:49:27 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = hashcount(zevpn->neigh_table);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2017-10-08 03:49:27 +02:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
|
|
|
wctx.json = json;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
|
|
|
|
&wctx);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of ARPs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_print_neigh_hdr(vty, &wctx);
|
2017-10-08 03:49:27 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx);
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display neighbors across all VNIs (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-11-04 19:17:29 +01:00
|
|
|
bool print_dup, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
2018-11-04 19:17:29 +01:00
|
|
|
void *args[3];
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2018-11-04 19:17:29 +01:00
|
|
|
args[2] = (void *)(ptrdiff_t)print_dup;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2020-07-23 23:51:10 +02:00
|
|
|
void *))zevpn_print_neigh_hash_all_evpn,
|
2017-10-08 03:49:27 +02:00
|
|
|
args);
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 10:56:52 +01:00
|
|
|
/*
|
|
|
|
* Display neighbors across all VNIs in detail(VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
bool print_dup, bool use_json)
|
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[3];
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-22 10:56:52 +01:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
args[2] = (void *)(ptrdiff_t)print_dup;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2020-07-23 23:51:10 +02:00
|
|
|
void *))zevpn_print_neigh_hash_all_evpn_detail,
|
2018-11-22 10:56:52 +01:00
|
|
|
args);
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2018-11-22 10:56:52 +01:00
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/*
|
|
|
|
* Display specific neighbor for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf, vni_t vni,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct ipaddr *ip, bool use_json)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *n;
|
2017-10-08 03:49:27 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-10-08 03:49:27 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2017-10-08 03:49:27 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-06-22 01:37:51 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-07-24 00:30:23 +02:00
|
|
|
n = zebra_evpn_neigh_lookup(zevpn, ip);
|
2017-05-15 07:45:55 +02:00
|
|
|
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-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_print_neigh(n, vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, 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.
|
|
|
|
*/
|
|
|
|
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,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_neigh;
|
2017-05-15 07:45:55 +02:00
|
|
|
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
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-06-22 01:37:51 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = hashcount(zevpn->neigh_table);
|
2017-05-15 07:45:55 +02:00
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2017-05-15 07:45:55 +02:00
|
|
|
wctx.vty = vty;
|
2018-07-07 06:46:46 +02:00
|
|
|
wctx.addr_width = 15;
|
2017-05-15 07:45:55 +02:00
|
|
|
wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP;
|
|
|
|
wctx.r_vtep_ip = vtep_ip;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
|
|
|
|
&wctx);
|
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
/*
|
|
|
|
* Display Duplicate detected Neighbors for a VNI
|
|
|
|
* (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni,
|
|
|
|
bool use_json)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-04 19:17:29 +01:00
|
|
|
uint32_t num_neigh;
|
|
|
|
struct neigh_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2018-11-04 19:17:29 +01:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
vty_json(vty, json);
|
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2018-11-04 19:17:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = hashcount(zevpn->neigh_table);
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_neigh = num_dup_detected_neighs(zevpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!num_neigh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2018-11-04 19:17:29 +01:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.addr_width = 15;
|
|
|
|
wctx.json = json;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
|
|
|
|
&wctx);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of ARPs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_neigh);
|
2020-03-28 01:14:45 +01:00
|
|
|
vty_out(vty, "%*s %-6s %-8s %-17s %-30s\n",
|
2018-11-04 19:17:29 +01:00
|
|
|
-wctx.addr_width, "IP", "Type",
|
2020-03-28 01:14:45 +01:00
|
|
|
"State", "MAC", "Remote ES/VTEP");
|
2018-11-04 19:17:29 +01:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numArpNd", num_neigh);
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_print_dad_neigh_hash,
|
|
|
|
&wctx);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2018-11-04 19:17:29 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for a VNI (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
zebra: Evpn mac vni detail show command
New show command "show evpn mac vni xx detail [json]"
to display details of all the mac entries for the
requested VNI.
Output of show evpn mac vni xx detail json:
{
"numMacs":2,
"macs":{
"ca:be:63:7c:81:05":{
"type":"local",
"intf":"veth100",
"ifindex":8,
"uptime":"00:06:55",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false,
"syncNeighCount":0,
"neighbors":{
"active":[
"fe80::c8be:63ff:fe7c:8105"
],
"inactive":[
]
}
}
}
}
Also added remoteEs field in the JSON output of
"show evpn mac vni xx json".
Output of show evpn mac vni xx json:
"00:02:00:00:00:0d":{
"type":"remote",
"remoteEs":"03:44:38:39:ff:ff:02:00:00:02",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false
}
Signed-off-by: Pooja Jagadeesh Doijode <pdoijode@nvidia.com>
2023-01-04 00:17:58 +01:00
|
|
|
vni_t vni, bool use_json, bool detail)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-05-15 07:45:55 +02:00
|
|
|
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
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
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-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_valid_macs(zevpn);
|
2017-05-15 07:45:55 +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();
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2017-05-15 07:45:55 +02:00
|
|
|
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) {
|
zebra: Evpn mac vni detail show command
New show command "show evpn mac vni xx detail [json]"
to display details of all the mac entries for the
requested VNI.
Output of show evpn mac vni xx detail json:
{
"numMacs":2,
"macs":{
"ca:be:63:7c:81:05":{
"type":"local",
"intf":"veth100",
"ifindex":8,
"uptime":"00:06:55",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false,
"syncNeighCount":0,
"neighbors":{
"active":[
"fe80::c8be:63ff:fe7c:8105"
],
"inactive":[
]
}
}
}
}
Also added remoteEs field in the JSON output of
"show evpn mac vni xx json".
Output of show evpn mac vni xx json:
"00:02:00:00:00:0d":{
"type":"remote",
"remoteEs":"03:44:38:39:ff:ff:02:00:00:02",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false
}
Signed-off-by: Pooja Jagadeesh Doijode <pdoijode@nvidia.com>
2023-01-04 00:17:58 +01:00
|
|
|
if (detail) {
|
|
|
|
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
|
|
|
|
zevpn->vni, num_macs);
|
|
|
|
} else {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
|
|
|
vty_out(vty,
|
|
|
|
"Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
|
|
|
|
vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
|
|
|
|
"Type", "Flags", "Intf/Remote ES/VTEP", "VLAN",
|
|
|
|
"Seq #'s");
|
|
|
|
}
|
2017-06-22 01:37:51 +02:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
2017-05-15 07:45:55 +02:00
|
|
|
|
zebra: Evpn mac vni detail show command
New show command "show evpn mac vni xx detail [json]"
to display details of all the mac entries for the
requested VNI.
Output of show evpn mac vni xx detail json:
{
"numMacs":2,
"macs":{
"ca:be:63:7c:81:05":{
"type":"local",
"intf":"veth100",
"ifindex":8,
"uptime":"00:06:55",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false,
"syncNeighCount":0,
"neighbors":{
"active":[
"fe80::c8be:63ff:fe7c:8105"
],
"inactive":[
]
}
}
}
}
Also added remoteEs field in the JSON output of
"show evpn mac vni xx json".
Output of show evpn mac vni xx json:
"00:02:00:00:00:0d":{
"type":"remote",
"remoteEs":"03:44:38:39:ff:ff:02:00:00:02",
"localSequence":0,
"remoteSequence":0,
"detectionCount":0,
"isDuplicate":false
}
Signed-off-by: Pooja Jagadeesh Doijode <pdoijode@nvidia.com>
2023-01-04 00:17:58 +01:00
|
|
|
if (detail)
|
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash_detail,
|
|
|
|
&wctx);
|
|
|
|
else
|
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash,
|
|
|
|
&wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
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,
|
2018-11-04 19:17:29 +01:00
|
|
|
bool print_dup, bool use_json)
|
2017-05-15 07:45:55 +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
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2017-05-15 07:45:55 +02:00
|
|
|
wctx.vty = vty;
|
2017-06-22 01:37:51 +02:00
|
|
|
wctx.json = json;
|
2018-11-04 19:17:29 +01:00
|
|
|
wctx.print_dup = print_dup;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
/*
|
|
|
|
* Display MACs in detail for all VNIs (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
bool print_dup, bool use_json)
|
|
|
|
{
|
|
|
|
struct mac_walk_ctx wctx;
|
|
|
|
json_object *json = NULL;
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2018-11-22 09:18:10 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2018-11-22 09:18:10 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2018-11-22 09:18:10 +01:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json;
|
|
|
|
wctx.print_dup = print_dup;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn_detail,
|
2018-11-22 09:18:10 +01:00
|
|
|
&wctx);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2018-11-22 09:18:10 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for all VNIs (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
struct in_addr vtep_ip, bool use_json)
|
2017-05-15 07:45:55 +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-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2017-05-15 07:45:55 +02:00
|
|
|
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;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display specific MAC for a VNI, if present (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-10-26 22:57:23 +02:00
|
|
|
vni_t vni, struct ethaddr *macaddr,
|
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2018-10-26 22:57:23 +02:00
|
|
|
json_object *json = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
2018-10-26 22:57:23 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2018-10-26 22:57:23 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2018-10-26 22:57:23 +02:00
|
|
|
else
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:58:45 +02:00
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
2017-05-15 07:45:55 +02:00
|
|
|
if (!mac) {
|
2018-10-26 22:57:23 +02:00
|
|
|
if (use_json)
|
2023-04-04 14:38:28 +02:00
|
|
|
vty_json(vty, json);
|
2018-10-26 22:57:23 +02:00
|
|
|
else
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Requested MAC does not exist in VNI %u\n",
|
|
|
|
vni);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_print_mac(mac, vty, json);
|
2023-04-04 14:38:28 +02:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-04 19:17:29 +01:00
|
|
|
/* Print Duplicate MACs per VNI */
|
|
|
|
void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
|
|
|
|
struct zebra_vrf *zvrf,
|
|
|
|
vni_t vni, bool use_json)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-04 19:17:29 +01:00
|
|
|
struct mac_walk_ctx wctx;
|
|
|
|
uint32_t num_macs;
|
|
|
|
json_object *json = NULL;
|
|
|
|
json_object *json_mac = NULL;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return;
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2018-11-04 19:17:29 +01:00
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_valid_macs(zevpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_dup_detected_macs(zevpn);
|
2018-11-04 19:17:29 +01:00
|
|
|
if (!num_macs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json = json_object_new_object();
|
|
|
|
json_mac = json_object_new_object();
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2018-11-04 19:17:29 +01:00
|
|
|
wctx.vty = vty;
|
|
|
|
wctx.json = json_mac;
|
|
|
|
|
|
|
|
if (!use_json) {
|
|
|
|
vty_out(vty,
|
|
|
|
"Number of MACs (local and remote) known for this VNI: %u\n",
|
|
|
|
num_macs);
|
2020-03-29 17:43:55 +02:00
|
|
|
vty_out(vty, "%-17s %-6s %-5s %-30s %-5s\n", "MAC", "Type",
|
|
|
|
"Flags", "Intf/Remote ES/VTEP", "VLAN");
|
2018-11-04 19:17:29 +01:00
|
|
|
} else
|
|
|
|
json_object_int_add(json, "numMacs", num_macs);
|
|
|
|
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash, &wctx);
|
2018-11-04 19:17:29 +01:00
|
|
|
|
|
|
|
if (use_json) {
|
|
|
|
json_object_object_add(json, "macs", json_mac);
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2018-11-04 19:17:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
|
2020-10-04 01:12:31 +02:00
|
|
|
struct ethaddr *macaddr, char *errmsg,
|
|
|
|
size_t errmsg_len)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2018-11-04 19:55:39 +01:00
|
|
|
struct listnode *node = NULL;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *nbr = NULL;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-12-03 04:08:22 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(errmsg, errmsg_len, "VNI %u does not exist", vni);
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:58:45 +02:00
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!mac) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintf(errmsg, errmsg_len,
|
|
|
|
"Requested MAC does not exist in VNI %u\n", vni);
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(errmsg, errmsg_len,
|
|
|
|
"Requested MAC is not duplicate detected\n");
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all IPs as duplicate associcated with this MAC */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
|
|
|
/* For local neigh mark inactive so MACIP update is generated
|
|
|
|
* to BGP. This is a scenario where MAC update received
|
|
|
|
* and detected as duplicate which marked neigh as duplicate.
|
|
|
|
* Later local neigh update did not get a chance to relay
|
|
|
|
* to BGP. Similarly remote macip update, neigh needs to be
|
|
|
|
* installed locally.
|
|
|
|
*/
|
2018-12-15 03:34:06 +01:00
|
|
|
if (zvrf->dad_freeze &&
|
|
|
|
CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
2018-11-04 19:55:39 +01:00
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_rem_neigh_install(
|
|
|
|
zevpn, nbr, false /*was_static*/);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
mac->dad_count = 0;
|
|
|
|
mac->detect_start_time.tv_sec = 0;
|
|
|
|
mac->detect_start_time.tv_usec = 0;
|
|
|
|
mac->dad_dup_detect_time = 0;
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(mac->dad_mac_auto_recovery_timer);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2018-12-15 03:34:06 +01:00
|
|
|
/* warn-only action return */
|
|
|
|
if (!zvrf->dad_freeze)
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-12-15 03:34:06 +01:00
|
|
|
|
2018-11-04 19:55:39 +01:00
|
|
|
/* Local: Notify Peer VTEPs, Remote: Install the entry */
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
/* Inform to BGP */
|
2020-07-23 23:58:45 +02:00
|
|
|
if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
|
|
|
|
mac->flags, mac->loc_seq,
|
|
|
|
mac->es))
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
/* Process all neighbors associated with this MAC. */
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
|
|
|
|
0 /*es_change*/);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
/* Install the entry. */
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
|
2020-10-04 01:12:31 +02:00
|
|
|
struct ipaddr *ip, char *errmsg,
|
|
|
|
size_t errmsg_len)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *nbr;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2018-11-04 19:55:39 +01:00
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
char buf2[ETHER_ADDR_STRLEN];
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(errmsg, errmsg_len, "VNI %u does not exist\n", vni);
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
nbr = zebra_evpn_neigh_lookup(zevpn, ip);
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!nbr) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(errmsg, errmsg_len,
|
|
|
|
"Requested host IP does not exist in VNI %u\n", vni);
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ipaddr2str(&nbr->ip, buf, sizeof(buf));
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(errmsg, errmsg_len,
|
|
|
|
"Requested host IP %s is not duplicate detected\n",
|
|
|
|
buf);
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:58:45 +02:00
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, &nbr->emac);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
|
2020-10-04 01:12:31 +02:00
|
|
|
snprintfrr(
|
|
|
|
errmsg, errmsg_len,
|
2020-02-06 21:37:28 +01:00
|
|
|
"Requested IP's associated MAC %s is still in duplicate state\n",
|
2018-11-04 19:55:39 +01:00
|
|
|
prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)));
|
2020-02-06 21:37:28 +01:00
|
|
|
return -1;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("%s: clear neigh %s in dup state, flags 0x%x seq %u",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, buf, nbr->flags, nbr->loc_seq);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->detect_start_time.tv_usec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(nbr->dad_ip_auto_recovery_timer);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
|
2020-07-24 00:30:23 +02:00
|
|
|
zebra_evpn_neigh_send_add_to_client(zevpn->vni, ip, &nbr->emac,
|
|
|
|
nbr->mac, nbr->flags,
|
|
|
|
nbr->loc_seq);
|
2018-11-04 19:55:39 +01:00
|
|
|
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
|
|
|
struct mac_walk_ctx *wctx = ctxt;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
struct listnode *node = NULL;
|
2021-08-20 15:01:26 +02:00
|
|
|
struct zebra_neigh *nbr = NULL;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2021-08-19 22:33:53 +02:00
|
|
|
mac = (struct zebra_mac *)bucket->data;
|
2018-11-04 19:55:39 +01:00
|
|
|
if (!mac)
|
|
|
|
return;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn = wctx->zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
|
|
|
|
mac->dad_count = 0;
|
|
|
|
mac->detect_start_time.tv_sec = 0;
|
|
|
|
mac->detect_start_time.tv_usec = 0;
|
|
|
|
mac->dad_dup_detect_time = 0;
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(mac->dad_mac_auto_recovery_timer);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
/* Remove all IPs as duplicate associcated with this MAC */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
|
|
|
|
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)
|
|
|
|
&& nbr->dad_count)
|
|
|
|
ZEBRA_NEIGH_SET_INACTIVE(nbr);
|
|
|
|
|
|
|
|
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
|
|
|
|
nbr->dad_count = 0;
|
|
|
|
nbr->detect_start_time.tv_sec = 0;
|
|
|
|
nbr->dad_dup_detect_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Local: Notify Peer VTEPs, Remote: Install the entry */
|
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
|
|
|
|
/* Inform to BGP */
|
2020-07-23 23:58:45 +02:00
|
|
|
if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
|
|
|
|
mac->flags, mac->loc_seq,
|
|
|
|
mac->es))
|
2018-11-04 19:55:39 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Process all neighbors associated with this MAC. */
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
|
|
|
|
0 /*es_change*/);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
/* Install the entry. */
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
static void zevpn_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
|
2018-11-04 19:55:39 +01:00
|
|
|
void **args)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
2021-08-19 22:08:53 +02:00
|
|
|
zevpn = (struct zebra_evpn *)bucket->data;
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2018-11-04 19:55:39 +01:00
|
|
|
return;
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
zvrf = (struct zebra_vrf *)args[0];
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (hashcount(zevpn->neigh_table)) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&n_wctx, 0, sizeof(n_wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
n_wctx.zevpn = zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
n_wctx.zvrf = zvrf;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table,
|
|
|
|
zebra_evpn_clear_dup_neigh_hash, &n_wctx);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (num_valid_macs(zevpn)) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&m_wctx, 0, sizeof(m_wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
m_wctx.zevpn = zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
m_wctx.zvrf = zvrf;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni_all(struct zebra_vrf *zvrf)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
2020-02-06 21:37:28 +01:00
|
|
|
void *args[1];
|
2018-11-04 19:55:39 +01:00
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
args[0] = zvrf;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn_clear_dup_detect_hash_vni_all, args);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni)
|
2018-11-04 19:55:39 +01:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
struct mac_walk_ctx m_wctx;
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled())
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2021-02-14 15:35:07 +01:00
|
|
|
zlog_warn("VNI %u does not exist", vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
return CMD_WARNING;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (hashcount(zevpn->neigh_table)) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&n_wctx, 0, sizeof(n_wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
n_wctx.zevpn = zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
n_wctx.zvrf = zvrf;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table,
|
|
|
|
zebra_evpn_clear_dup_neigh_hash, &n_wctx);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (num_valid_macs(zevpn)) {
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&m_wctx, 0, sizeof(m_wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
m_wctx.zevpn = zevpn;
|
2018-11-04 19:55:39 +01:00
|
|
|
m_wctx.zvrf = zvrf;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx);
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2020-02-06 21:37:28 +01:00
|
|
|
return 0;
|
2018-11-04 19:55:39 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:45:55 +02:00
|
|
|
/*
|
|
|
|
* Display MACs for a VNI from specific VTEP (VTY command handler).
|
|
|
|
*/
|
|
|
|
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,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t num_macs;
|
2017-05-15 07:45:55 +02:00
|
|
|
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
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
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-05-15 07:45:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-07-23 23:51:10 +02:00
|
|
|
num_macs = num_valid_macs(zevpn);
|
2017-05-15 07:45:55 +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();
|
|
|
|
}
|
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&wctx, 0, sizeof(wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
wctx.zevpn = zevpn;
|
2017-05-15 07:45:55 +02:00
|
|
|
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;
|
2020-07-23 23:58:45 +02:00
|
|
|
hash_iterate(zevpn->mac_table, zebra_evpn_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);
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI information (VTY command handler).
|
2019-11-22 01:18:04 +01:00
|
|
|
*
|
|
|
|
* use_json flag indicates that output should be in JSON format.
|
|
|
|
* json_array is non NULL when JSON output needs to be aggregated (by the
|
|
|
|
* caller) and then printed, otherwise, JSON evpn vni info is printed
|
|
|
|
* right away.
|
2017-05-15 07:45:55 +02:00
|
|
|
*/
|
2017-06-22 01:37:51 +02:00
|
|
|
void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
|
2019-11-22 01:18:04 +01:00
|
|
|
bool use_json, json_object *json_array)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
2019-11-22 01:18:04 +01:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2018-02-10 01:57:37 +01:00
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-11-15 10:01:00 +01:00
|
|
|
zl3vni_print(zl3vni, (void *)args);
|
|
|
|
} else {
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (zevpn)
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_print(zevpn, (void *)args);
|
2019-11-22 01:18:04 +01:00
|
|
|
else if (!json)
|
|
|
|
vty_out(vty, "%% VNI %u does not exist\n", vni);
|
2017-11-15 10:01:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
if (use_json) {
|
2019-11-22 01:18:04 +01:00
|
|
|
/*
|
|
|
|
* Each "json" object contains info about 1 VNI.
|
|
|
|
* When "json_array" is non-null, we aggreggate the json output
|
|
|
|
* into json_array and print it as a JSON array.
|
|
|
|
*/
|
|
|
|
if (json_array)
|
|
|
|
json_object_array_add(json_array, json);
|
2021-11-25 23:02:37 +01:00
|
|
|
else
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all global details for EVPN */
|
2018-09-04 19:39:04 +02:00
|
|
|
void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
|
2017-05-15 07:45:55 +02:00
|
|
|
{
|
2017-11-15 10:01:00 +01:00
|
|
|
int num_l2vnis = 0;
|
|
|
|
int num_l3vnis = 0;
|
2017-12-07 17:28:04 +01:00
|
|
|
int num_vnis = 0;
|
2017-06-22 01:37:51 +02:00
|
|
|
json_object *json = NULL;
|
2017-11-15 10:01:00 +01:00
|
|
|
struct zebra_vrf *zvrf = NULL;
|
2017-05-15 07:45:55 +02:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (uj)
|
|
|
|
json = json_object_new_object();
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2019-03-06 19:15:10 +01:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2018-08-27 16:43:37 +02:00
|
|
|
num_l3vnis = hashcount(zrouter.l3vni_table);
|
2020-07-23 23:51:10 +02:00
|
|
|
num_l2vnis = hashcount(zvrf->evpn_table);
|
2017-12-07 17:28:04 +01:00
|
|
|
num_vnis = num_l2vnis + num_l3vnis;
|
2017-11-15 10:01:00 +01:00
|
|
|
|
|
|
|
if (uj) {
|
2017-07-07 01:33:50 +02:00
|
|
|
json_object_string_add(json, "advertiseGatewayMacip",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
zebra: Add missing json attributes for show evpn
Missing json attributes added for show evpn json
Before:
```
tor-1# show evpn json
{
"advertiseGatewayMacip":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0,
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"--:--:--",
"uplinkConfigCount":0,
"uplinkActiveCount":0
}
tor-1#
```
After:
```
tor-1# show evpn json
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0,
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"--:--:--",
"uplinkConfigCount":0,
"uplinkActiveCount":0
}
tor-1#
```
Ticket:#3323248
Issue:3323248
Testing: UT done
Signed-off-by: Sindhu Parvathi Gopinathan's <sgopinathan@nvidia.com>
2023-01-07 04:54:49 +01:00
|
|
|
json_object_string_add(json, "advertiseSviMacip",
|
|
|
|
zvrf->advertise_svi_macip ? "Yes"
|
|
|
|
: "No");
|
|
|
|
json_object_string_add(json, "advertiseSviMac",
|
|
|
|
zebra_evpn_mh_do_adv_svi_mac() ? "Yes"
|
|
|
|
: "No");
|
2017-12-07 17:28:04 +01:00
|
|
|
json_object_int_add(json, "numVnis", num_vnis);
|
2017-11-15 10:01:00 +01:00
|
|
|
json_object_int_add(json, "numL2Vnis", num_l2vnis);
|
|
|
|
json_object_int_add(json, "numL3Vnis", num_l3vnis);
|
2020-05-11 03:02:37 +02:00
|
|
|
if (zebra_evpn_do_dup_addr_detect(zvrf))
|
2018-11-17 02:51:11 +01:00
|
|
|
json_object_boolean_true_add(json,
|
|
|
|
"isDuplicateAddrDetection");
|
|
|
|
else
|
|
|
|
json_object_boolean_false_add(json,
|
|
|
|
"isDuplicateAddrDetection");
|
|
|
|
json_object_int_add(json, "maxMoves", zvrf->dad_max_moves);
|
|
|
|
json_object_int_add(json, "detectionTime", zvrf->dad_time);
|
|
|
|
json_object_int_add(json, "detectionFreezeTime",
|
|
|
|
zvrf->dad_freeze_time);
|
zebra: add evpn isDetectionFreeze to json output
Added "isDetectionFreeze" for show evpn json output to identify the
default and freeze permanent config.
Before fix:-
```
tor-2(config)# router bgp 65561
tor-2(config-router)# address-family l2vpn evpn
<cr>
tor-2(config-router)# address-family l2vpn evpn
tor-2(config-router-af)# dup-addr-detection freeze permanent
tor-2(config-router-af)# do show evpn
L2 VNIs: 21
L3 VNIs: 5
Advertise gateway mac-ip: No
Advertise svi mac-ip: No
Advertise svi mac: No
Duplicate address detection: Enable
Detection max-moves 5, time 180
Detection freeze permanent
EVPN MH:
mac-holdtime: 1080s, neigh-holdtime: 1080s
startup-delay: 180s, start-delay-timer: --:--:--
uplink-cfg-cnt: 0, uplink-active-cnt: 0
tor-2(config-router-af)#
tor-2(config-router-af)# do show evpn json
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0,
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"--:--:--",
"uplinkConfigCount":0,
"uplinkActiveCount":0
}
tor-2(config-router-af)#
```
After fix:-
```
cumulus@tor-1:mgmt:~$ sudo vtysh -c "show evpn json"
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0, ==> default case , i.e dad_freeze duration is 0
"isDetectionFreeze":false, ==> default case, i.e. dad_freeze disabled
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"--:--:--",
"uplinkConfigCount":0,
"uplinkActiveCount":0
}
cumulus@tor-1:mgmt:~$
tor-1(config-router-af)# dup-addr-detection freeze permanent
tor-1(config-router-af)# do show evpn json
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0, ==> dad_freeze with duration permanent
"isDetectionFreeze":true, ==> dad_freeze enabled
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"00:00:08",
"uplinkConfigCount":0,
"uplinkActiveCount":0,
"protodownReasons":[
"startupDelay"
]
}
tor-1(config-router-af)#
tor-1(config-router-af)# dup-addr-detection freeze 400
tor-1(config-router-af)#
tor-1(config-router-af)# do show evpn json
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":400, ==> dad_freeze duration with numeric value
"isDetectionFreeze":true, ==> dad_freeze enabled
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"00:00:47",
"uplinkConfigCount":0,
"uplinkActiveCount":0,
"protodownReasons":[
"startupDelay"
]
}
tor-1(config-router-af)# no dup-addr-detection freeze permanent
tor-1(config-router-af)# do show evpn json
{
"advertiseGatewayMacip":"No",
"advertiseSviMacip":"No",
"advertiseSviMac":"No",
"numVnis":26,
"numL2Vnis":21,
"numL3Vnis":5,
"isDuplicateAddrDetection":true,
"maxMoves":5,
"detectionTime":180,
"detectionFreezeTime":0, ==> no dad_freeze duration
"isDetectionFreeze":false, ==> no dad_freeze enabled
"macHoldtime":1080,
"neighHoldtime":1080,
"startupDelay":180,
"startupDelayTimer":"--:--:--",
"uplinkConfigCount":0,
"uplinkActiveCount":0
}
tor-1(config-router-af)#
```
Ticket:#3404283
Issue:3404283
Testing: UT done
Signed-off-by: Sindhu Parvathi Gopinathan's <sgopinathan@nvidia.com>
2023-03-18 19:48:34 +01:00
|
|
|
json_object_boolean_add(json, "isDetectionFreeze",
|
|
|
|
zvrf->dad_freeze);
|
zebra: uplink tracking and startup delay for EVPN-MH
Local ethernet segments are held in a protodown or error-disabled state
if access to the VxLAN overlay is not ready -
1. When FRR comes up the local-ESs/access-port are kept protodown
for the startup-delay duration. During this time the underlay and
EVPN routes via it are expected to converge.
2. When all the uplinks/core-links attached to the underlay go down
the access-ports are similarly protodowned.
The ES-bond protodown state is propagated to each ES-bond member
and programmed in the dataplane/kernel (per-bond-member).
Configuring uplinks -
vtysh -c "conf t" vtysh -c "interface swp4" vtysh -c "evpn mh uplink"
Configuring startup delay -
vtysh -c "conf t" vtysh -c "evpn mh startup-delay 100"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EVPN protodown display -
========================
root@torm-11:mgmt:~# vtysh -c "show evpn"
L2 VNIs: 10
L3 VNIs: 3
Advertise gateway mac-ip: No
Advertise svi mac-ip: No
Duplicate address detection: Disable
Detection max-moves 5, time 180
EVPN MH:
mac-holdtime: 60s, neigh-holdtime: 60s
startup-delay: 180s, start-delay-timer: 00:01:14 <<<<<<<<<<<<
uplink-cfg-cnt: 4, uplink-active-cnt: 4
protodown: startup-delay <<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ES-bond protodown display -
===========================
root@torm-11:mgmt:~# vtysh -c "show interface hostbond1"
Interface hostbond1 is up, line protocol is down
Link ups: 0 last: (never)
Link downs: 1 last: 2020/04/26 20:38:03.53
PTM status: disabled
vrf: default
OS Description: Local Node/s torm-11 and Ports swp5 <==> Remote Node/s hostd-11 and Ports swp1
index 58 metric 0 mtu 9152 speed 4294967295
flags: <UP,BROADCAST,MULTICAST>
Type: Ethernet
HWaddr: 00:02:00:00:00:35
Interface Type bond
Master interface: bridge
EVPN-MH: ES id 1 ES sysmac 00:00:00:00:01:11
protodown: off rc: startup-delay <<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ES-bond member protodown display -
==================================
root@torm-11:mgmt:~# vtysh -c "show interface swp5"
Interface swp5 is up, line protocol is down
Link ups: 0 last: (never)
Link downs: 3 last: 2020/04/26 20:38:03.52
PTM status: disabled
vrf: default
index 7 metric 0 mtu 9152 speed 10000
flags: <UP,BROADCAST,MULTICAST>
Type: Ethernet
HWaddr: 00:02:00:00:00:35
Interface Type Other
Master interface: hostbond1
protodown: on rc: startup-delay <<<<<<<<<<<<<<<<
root@torm-11:mgmt:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-05-09 04:11:13 +02:00
|
|
|
zebra_evpn_mh_json(json);
|
2017-06-22 01:37:51 +02:00
|
|
|
} else {
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "L2 VNIs: %u\n", num_l2vnis);
|
|
|
|
vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
|
2017-07-07 01:33:50 +02:00
|
|
|
vty_out(vty, "Advertise gateway mac-ip: %s\n",
|
|
|
|
zvrf->advertise_gw_macip ? "Yes" : "No");
|
2019-02-05 17:38:35 +01:00
|
|
|
vty_out(vty, "Advertise svi mac-ip: %s\n",
|
|
|
|
zvrf->advertise_svi_macip ? "Yes" : "No");
|
2020-11-02 19:53:50 +01:00
|
|
|
vty_out(vty, "Advertise svi mac: %s\n",
|
|
|
|
zebra_evpn_mh_do_adv_svi_mac() ? "Yes" : "No");
|
2018-11-17 02:51:11 +01:00
|
|
|
vty_out(vty, "Duplicate address detection: %s\n",
|
2020-05-11 03:02:37 +02:00
|
|
|
zebra_evpn_do_dup_addr_detect(zvrf) ? "Enable"
|
|
|
|
: "Disable");
|
2018-11-17 02:51:11 +01:00
|
|
|
vty_out(vty, " Detection max-moves %u, time %d\n",
|
|
|
|
zvrf->dad_max_moves, zvrf->dad_time);
|
|
|
|
if (zvrf->dad_freeze) {
|
|
|
|
if (zvrf->dad_freeze_time)
|
|
|
|
vty_out(vty, " Detection freeze %u\n",
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
else
|
|
|
|
vty_out(vty, " Detection freeze %s\n",
|
|
|
|
"permanent");
|
|
|
|
}
|
zebra: uplink tracking and startup delay for EVPN-MH
Local ethernet segments are held in a protodown or error-disabled state
if access to the VxLAN overlay is not ready -
1. When FRR comes up the local-ESs/access-port are kept protodown
for the startup-delay duration. During this time the underlay and
EVPN routes via it are expected to converge.
2. When all the uplinks/core-links attached to the underlay go down
the access-ports are similarly protodowned.
The ES-bond protodown state is propagated to each ES-bond member
and programmed in the dataplane/kernel (per-bond-member).
Configuring uplinks -
vtysh -c "conf t" vtysh -c "interface swp4" vtysh -c "evpn mh uplink"
Configuring startup delay -
vtysh -c "conf t" vtysh -c "evpn mh startup-delay 100"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
EVPN protodown display -
========================
root@torm-11:mgmt:~# vtysh -c "show evpn"
L2 VNIs: 10
L3 VNIs: 3
Advertise gateway mac-ip: No
Advertise svi mac-ip: No
Duplicate address detection: Disable
Detection max-moves 5, time 180
EVPN MH:
mac-holdtime: 60s, neigh-holdtime: 60s
startup-delay: 180s, start-delay-timer: 00:01:14 <<<<<<<<<<<<
uplink-cfg-cnt: 4, uplink-active-cnt: 4
protodown: startup-delay <<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ES-bond protodown display -
===========================
root@torm-11:mgmt:~# vtysh -c "show interface hostbond1"
Interface hostbond1 is up, line protocol is down
Link ups: 0 last: (never)
Link downs: 1 last: 2020/04/26 20:38:03.53
PTM status: disabled
vrf: default
OS Description: Local Node/s torm-11 and Ports swp5 <==> Remote Node/s hostd-11 and Ports swp1
index 58 metric 0 mtu 9152 speed 4294967295
flags: <UP,BROADCAST,MULTICAST>
Type: Ethernet
HWaddr: 00:02:00:00:00:35
Interface Type bond
Master interface: bridge
EVPN-MH: ES id 1 ES sysmac 00:00:00:00:01:11
protodown: off rc: startup-delay <<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ES-bond member protodown display -
==================================
root@torm-11:mgmt:~# vtysh -c "show interface swp5"
Interface swp5 is up, line protocol is down
Link ups: 0 last: (never)
Link downs: 3 last: 2020/04/26 20:38:03.52
PTM status: disabled
vrf: default
index 7 metric 0 mtu 9152 speed 10000
flags: <UP,BROADCAST,MULTICAST>
Type: Ethernet
HWaddr: 00:02:00:00:00:35
Interface Type Other
Master interface: hostbond1
protodown: on rc: startup-delay <<<<<<<<<<<<<<<<
root@torm-11:mgmt:~#
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2020-05-09 04:11:13 +02:00
|
|
|
zebra_evpn_mh_print(vty);
|
2017-06-22 01:37:51 +02:00
|
|
|
}
|
2017-11-15 10:01:00 +01:00
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (uj)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-11-15 10:01:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display VNI hash table (VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
|
2018-08-29 14:19:54 +02:00
|
|
|
bool use_json)
|
2017-11-15 10:01:00 +01:00
|
|
|
{
|
|
|
|
json_object *json = NULL;
|
|
|
|
void *args[2];
|
|
|
|
|
|
|
|
if (use_json)
|
|
|
|
json = json_object_new_object();
|
2023-04-04 14:38:28 +02:00
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
vty_json(vty, json);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!use_json)
|
2017-11-15 10:01:00 +01:00
|
|
|
vty_out(vty, "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n", "VNI",
|
|
|
|
"Type", "VxLAN IF", "# MACs", "# ARPs",
|
|
|
|
"# Remote VTEPs", "Tenant VRF");
|
|
|
|
|
2017-06-22 01:37:51 +02:00
|
|
|
args[0] = vty;
|
|
|
|
args[1] = json;
|
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all L2-VNIs */
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(
|
|
|
|
zvrf->evpn_table,
|
|
|
|
(void (*)(struct hash_bucket *, void *))zebra_evpn_print_hash,
|
|
|
|
args);
|
2017-06-22 01:37:51 +02:00
|
|
|
|
2017-11-15 10:01:00 +01:00
|
|
|
/* Display all L3-VNIs */
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *, void *))zl3vni_print_hash,
|
2017-11-15 10:01:00 +01:00
|
|
|
args);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json);
|
2017-05-15 07:45:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 01:55:07 +01:00
|
|
|
void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int time = 0;
|
|
|
|
uint32_t max_moves = 0;
|
|
|
|
uint32_t freeze_time = 0;
|
|
|
|
bool dup_addr_detect = false;
|
|
|
|
bool freeze = false;
|
2020-05-11 03:02:37 +02:00
|
|
|
bool old_addr_detect;
|
2018-11-02 01:55:07 +01:00
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETL(s, dup_addr_detect);
|
|
|
|
STREAM_GETL(s, time);
|
|
|
|
STREAM_GETL(s, max_moves);
|
|
|
|
STREAM_GETL(s, freeze);
|
|
|
|
STREAM_GETL(s, freeze_time);
|
|
|
|
|
2020-05-11 03:02:37 +02:00
|
|
|
old_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf);
|
|
|
|
zvrf->dup_addr_detect = dup_addr_detect;
|
|
|
|
dup_addr_detect = zebra_evpn_do_dup_addr_detect(zvrf);
|
|
|
|
|
2018-11-04 19:55:39 +01:00
|
|
|
/* DAD previous state was enabled, and new state is disable,
|
|
|
|
* clear all duplicate detected addresses.
|
|
|
|
*/
|
2020-05-11 03:02:37 +02:00
|
|
|
if (old_addr_detect && !dup_addr_detect)
|
2020-02-06 21:37:28 +01:00
|
|
|
zebra_vxlan_clear_dup_detect_vni_all(zvrf);
|
2018-11-04 19:55:39 +01:00
|
|
|
|
2018-11-02 01:55:07 +01:00
|
|
|
zvrf->dad_time = time;
|
|
|
|
zvrf->dad_max_moves = max_moves;
|
|
|
|
zvrf->dad_freeze = freeze;
|
|
|
|
zvrf->dad_freeze_time = freeze_time;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2019-01-03 01:48:32 +01:00
|
|
|
"VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
|
|
|
|
vrf_id_to_name(zvrf->vrf->vrf_id),
|
2020-05-11 03:02:37 +02:00
|
|
|
dup_addr_detect ? "enable" : "disable",
|
|
|
|
zvrf->dad_max_moves, zvrf->dad_time,
|
2018-11-02 01:55:07 +01:00
|
|
|
zvrf->dad_freeze ? "enable" : "disable",
|
|
|
|
zvrf->dad_freeze_time);
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:33:43 +01:00
|
|
|
/*
|
|
|
|
* Display VNI hash table in detail(VTY command handler).
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf,
|
|
|
|
bool use_json)
|
|
|
|
{
|
2019-11-22 01:18:04 +01:00
|
|
|
json_object *json_array = NULL;
|
2018-11-15 18:33:43 +01:00
|
|
|
struct zebra_ns *zns = NULL;
|
2020-08-10 18:40:48 +02:00
|
|
|
struct zebra_evpn_show zes;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
2023-04-04 14:38:28 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
if (use_json)
|
|
|
|
vty_out(vty, "{}\n");
|
2018-11-15 18:33:43 +01:00
|
|
|
return;
|
2023-04-04 14:38:28 +02:00
|
|
|
}
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
zns = zebra_ns_lookup(NS_DEFAULT);
|
|
|
|
if (!zns)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (use_json)
|
2019-11-22 01:18:04 +01:00
|
|
|
json_array = json_object_new_array();
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
zes.vty = vty;
|
2019-11-22 01:18:04 +01:00
|
|
|
zes.json = json_array;
|
2018-11-15 18:33:43 +01:00
|
|
|
zes.zvrf = zvrf;
|
2019-11-22 01:18:04 +01:00
|
|
|
zes.use_json = use_json;
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
/* Display all L2-VNIs */
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
|
|
|
(void (*)(struct hash_bucket *,
|
|
|
|
void *))zebra_evpn_print_hash_detail,
|
|
|
|
&zes);
|
2018-11-15 18:33:43 +01:00
|
|
|
|
|
|
|
/* Display all L3-VNIs */
|
|
|
|
hash_iterate(zrouter.l3vni_table,
|
2019-02-19 16:46:52 +01:00
|
|
|
(void (*)(struct hash_bucket *,
|
2018-11-15 18:33:43 +01:00
|
|
|
void *))zl3vni_print_hash_detail,
|
|
|
|
&zes);
|
|
|
|
|
2021-11-25 23:02:37 +01:00
|
|
|
if (use_json)
|
2021-11-25 16:49:46 +01:00
|
|
|
vty_json(vty, json_array);
|
2018-11-15 18:33:43 +01:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
2018-03-03 00:28:33 +01:00
|
|
|
* Handle neighbor delete notification from the kernel (on a VLAN device
|
|
|
|
* / L3 interface). This may result in either the neighbor getting deleted
|
|
|
|
* from our database or being re-added to the kernel (if it is a valid
|
2017-05-15 07:44:13 +02:00
|
|
|
* remote neighbor).
|
|
|
|
*/
|
2018-03-03 00:28:33 +01:00
|
|
|
int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
|
|
|
|
struct interface *link_if,
|
|
|
|
struct ipaddr *ip)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-10-22 10:16:54 +02:00
|
|
|
/* check if this is a remote neigh entry corresponding to remote
|
2017-12-27 20:47:10 +01:00
|
|
|
* next-hop
|
|
|
|
*/
|
2017-10-22 10:16:54 +02:00
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni)
|
|
|
|
return zl3vni_local_nh_del(zl3vni, ip);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, link_if);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2019-07-26 23:57:59 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"%s: Del neighbor %pIA EVPN is not present for interface %s",
|
|
|
|
__func__, ip, ifp->name);
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2019-07-26 23:57:59 +02:00
|
|
|
}
|
2017-10-22 10:16:54 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2017-05-15 07:44:13 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon local neighbor DEL",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, zevpn);
|
2017-05-15 07:44:13 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2021-03-12 02:44:45 +01:00
|
|
|
zlog_debug("Del neighbor %pIA intf %s(%u) -> L2-VNI %u",
|
|
|
|
ip, ifp->name, ifp->ifindex, zevpn->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-04-24 16:04:19 +02:00
|
|
|
return zebra_evpn_neigh_del_ip(zevpn, ip);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-03-03 00:28:33 +01:00
|
|
|
* Handle neighbor add or update notification from the kernel (on a VLAN
|
|
|
|
* device / L3 interface). This is typically for a local neighbor but can
|
|
|
|
* also be for a remote neighbor (e.g., ageout notification). It could
|
|
|
|
* also be a "move" scenario.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2018-03-03 00:28:33 +01:00
|
|
|
int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
|
|
|
|
struct interface *link_if,
|
|
|
|
struct ipaddr *ip,
|
|
|
|
struct ethaddr *macaddr,
|
|
|
|
uint16_t state,
|
2018-09-10 19:13:20 +02:00
|
|
|
bool is_ext,
|
2020-03-29 17:43:55 +02:00
|
|
|
bool is_router,
|
|
|
|
bool local_inactive, bool dp_static)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-11-09 18:13:28 +01:00
|
|
|
|
|
|
|
/* check if this is a remote neigh entry corresponding to remote
|
|
|
|
* next-hop
|
|
|
|
*/
|
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni)
|
|
|
|
return zl3vni_local_nh_add_update(zl3vni, ip, state);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* We are only interested in neighbors on an SVI that resides on top
|
|
|
|
* of a VxLAN bridge.
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, link_if);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-29 17:43:55 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
|
2017-05-15 07:44:13 +02:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Add/Update neighbor %pIA MAC %pEA intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u",
|
|
|
|
ip, macaddr, ifp->name,
|
2018-09-10 19:13:20 +02:00
|
|
|
ifp->ifindex, state, is_ext ? "ext-learned " : "",
|
|
|
|
is_router ? "router " : "",
|
2020-03-29 17:43:55 +02:00
|
|
|
local_inactive ? "local_inactive " : "",
|
2020-08-08 03:32:52 +02:00
|
|
|
dp_static ? "peer_sync " : "", zevpn->vni);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-03 00:28:33 +01:00
|
|
|
/* Is this about a local neighbor or a remote one? */
|
2018-09-10 19:13:20 +02:00
|
|
|
if (!is_ext)
|
2020-07-24 00:30:23 +02:00
|
|
|
return zebra_evpn_local_neigh_update(zevpn, ifp, ip, macaddr,
|
|
|
|
is_router, local_inactive,
|
|
|
|
dp_static);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2020-07-24 00:30:23 +02:00
|
|
|
return zebra_evpn_remote_neigh_update(zevpn, ifp, ip, macaddr, state);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
static int32_t
|
|
|
|
zebra_vxlan_remote_macip_helper(bool add, struct stream *s, vni_t *vni,
|
|
|
|
struct ethaddr *macaddr, uint16_t *ipa_len,
|
|
|
|
struct ipaddr *ip, struct in_addr *vtep_ip,
|
2020-03-28 01:14:45 +01:00
|
|
|
uint8_t *flags, uint32_t *seq, esi_t *esi)
|
2020-01-03 19:30:37 +01:00
|
|
|
{
|
|
|
|
uint16_t l = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain each remote MACIP and process.
|
|
|
|
* Message contains VNI, followed by MAC followed by IP (if any)
|
|
|
|
* followed by remote VTEP IP.
|
|
|
|
*/
|
|
|
|
memset(ip, 0, sizeof(*ip));
|
|
|
|
STREAM_GETL(s, *vni);
|
|
|
|
STREAM_GET(macaddr->octet, s, ETH_ALEN);
|
2020-09-23 21:31:52 +02:00
|
|
|
STREAM_GETW(s, *ipa_len);
|
2020-01-03 19:30:37 +01:00
|
|
|
|
|
|
|
if (*ipa_len) {
|
|
|
|
if (*ipa_len == IPV4_MAX_BYTELEN)
|
|
|
|
ip->ipa_type = IPADDR_V4;
|
|
|
|
else if (*ipa_len == IPV6_MAX_BYTELEN)
|
|
|
|
ip->ipa_type = IPADDR_V6;
|
|
|
|
else {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"ipa_len *must* be %d or %d bytes in length not %d",
|
|
|
|
IPV4_MAX_BYTELEN, IPV6_MAX_BYTELEN,
|
|
|
|
*ipa_len);
|
|
|
|
goto stream_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
STREAM_GET(&ip->ip.addr, s, *ipa_len);
|
|
|
|
}
|
|
|
|
l += 4 + ETH_ALEN + 4 + *ipa_len;
|
|
|
|
STREAM_GET(&vtep_ip->s_addr, s, IPV4_MAX_BYTELEN);
|
|
|
|
l += IPV4_MAX_BYTELEN;
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
STREAM_GETC(s, *flags);
|
|
|
|
STREAM_GETL(s, *seq);
|
|
|
|
l += 5;
|
2020-03-28 01:14:45 +01:00
|
|
|
STREAM_GET(esi, s, sizeof(esi_t));
|
|
|
|
l += sizeof(esi_t);
|
2020-01-03 19:30:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return l;
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return -1;
|
|
|
|
}
|
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.
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t l = 0, ipa_len;
|
2017-05-15 07:44:13 +02:00
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2020-01-03 19:30:37 +01:00
|
|
|
int res_length = zebra_vxlan_remote_macip_helper(
|
|
|
|
false, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, NULL,
|
2020-03-28 01:14:45 +01:00
|
|
|
NULL, NULL);
|
2020-01-03 18:55:09 +01:00
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
if (res_length == -1)
|
|
|
|
goto stream_failure;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
l += res_length;
|
2017-05-15 07:44:13 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Recv MACIP DEL VNI %u MAC %pEA%s%s Remote VTEP %pI4 from %s",
|
|
|
|
vni, &macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
|
2020-10-21 19:57:06 +02:00
|
|
|
&vtep_ip, zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-19 21:25:27 +02:00
|
|
|
/* Enqueue to workqueue for processing */
|
|
|
|
zebra_rib_queue_evpn_rem_macip_del(vni, &macaddr, &ip, vtep_ip);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
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).
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:44:13 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
vni_t vni;
|
|
|
|
struct ethaddr macaddr;
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct in_addr vtep_ip;
|
2018-08-20 23:31:30 +02:00
|
|
|
uint16_t l = 0, ipa_len;
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
uint8_t flags = 0;
|
|
|
|
uint32_t seq;
|
2017-05-15 07:44:13 +02:00
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2020-03-28 01:14:45 +01:00
|
|
|
esi_t esi;
|
|
|
|
char esi_buf[ESI_STR_LEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("EVPN not enabled, ignoring remote MACIP ADD");
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2021-04-19 21:25:27 +02:00
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
int res_length = zebra_vxlan_remote_macip_helper(
|
|
|
|
true, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip,
|
2020-03-28 01:14:45 +01:00
|
|
|
&flags, &seq, &esi);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
if (res_length == -1)
|
|
|
|
goto stream_failure;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-01-03 19:30:37 +01:00
|
|
|
l += res_length;
|
2020-03-28 01:14:45 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN) {
|
|
|
|
if (memcmp(&esi, zero_esi, sizeof(esi_t)))
|
|
|
|
esi_to_str(&esi, esi_buf, sizeof(esi_buf));
|
|
|
|
else
|
2020-06-16 02:24:39 +02:00
|
|
|
strlcpy(esi_buf, "-", ESI_STR_LEN);
|
2017-05-15 23:42:57 +02:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Recv %sMACIP ADD VNI %u MAC %pEA%s%s flags 0x%x seq %u VTEP %pI4 ESI %s from %s",
|
2020-03-29 17:43:55 +02:00
|
|
|
(flags & ZEBRA_MACIP_TYPE_SYNC_PATH) ?
|
|
|
|
"sync-" : "",
|
2021-03-12 02:44:45 +01:00
|
|
|
vni, &macaddr,
|
bgpd, zebra: EVPN extended mobility support
Implement procedures similar to what is specified in
https://tools.ietf.org/html/draft-malhotra-bess-evpn-irb-extended-mobility
in order to support extended mobility scenarios in EVPN. These are scenarios
where a host/VM move results in a different (MAC,IP) binding from earlier.
For example, a host with an address assignment (IP1, MAC1) moves behind a
different PE (VTEP) and has an address assignment of (IP1, MAC2) or a host
with an address assignment (IP5, MAC5) has a different assignment of (IP6,
MAC5) after the move. Note that while these are described as "move" scenarios,
they also cover the situation when a VM is shut down and a new VM is spun up
at a different location that reuses the IP address or MAC address of the
earlier instance, but not both. Yet another scenario is a MAC change for an
attached host/VM i.e., when the MAC of an attached host changes from MAC1 to
MAC2. This is necessary because there may already be a non-zero sequence
number associated with MAC2. Also, even though (IP, MAC1) is withdrawn before
(IP, MAC2) is advertised, they may propagate through the network differently.
The procedures continue to rely on the MAC mobility extended community
specified in RFC 7432 and already supported by the implementation, but
augment it with a inheritance mechanism that understands the relationship
of the host MACIP (ARP/neighbor table entry) to the underlying MAC (MAC
forwarding database entry). In FRR, this relationship is understood by the
zebra component which doubles as the "host mobility manager", so the MAC
mobility sequence numbers are determined through interaction between bgpd
and zebra.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
2018-08-20 21:20:06 +02:00
|
|
|
ipa_len ? " IP " : "",
|
|
|
|
ipa_len ?
|
|
|
|
ipaddr2str(&ip, buf1, sizeof(buf1)) : "",
|
2020-10-21 19:57:06 +02:00
|
|
|
flags, seq, &vtep_ip, esi_buf,
|
2017-05-15 07:44:13 +02:00
|
|
|
zebra_route_string(client->proto));
|
2020-03-28 01:14:45 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-19 21:25:27 +02:00
|
|
|
/* Enqueue to workqueue for processing */
|
|
|
|
zebra_rib_queue_evpn_rem_macip_add(vni, &macaddr, &ip, flags,
|
|
|
|
seq, vtep_ip, &esi);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2019-09-06 06:11:07 +02:00
|
|
|
/*
|
|
|
|
* Handle remote vtep delete by kernel; re-add the vtep if we have it
|
|
|
|
*/
|
2021-07-27 09:47:52 +02:00
|
|
|
int zebra_vxlan_check_readd_vtep(struct interface *ifp, vni_t vni,
|
2019-09-06 06:11:07 +02:00
|
|
|
struct in_addr vtep_ip)
|
|
|
|
{
|
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_vrf *zvrf = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-19 22:13:39 +02:00
|
|
|
struct zebra_vtep *zvtep = NULL;
|
2021-07-27 09:47:52 +02:00
|
|
|
struct zebra_vxlan_vni *vnip;
|
2019-09-06 06:11:07 +02:00
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
|
|
|
|
/* If EVPN is not enabled, nothing to do. */
|
|
|
|
if (!is_evpn_enabled())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Locate VRF corresponding to interface. */
|
2021-10-22 00:17:40 +02:00
|
|
|
zvrf = ifp->vrf->info;
|
2019-09-06 06:11:07 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return -1;
|
|
|
|
|
2021-07-27 09:47:52 +02:00
|
|
|
vnip = zebra_vxlan_if_vni_find(zif, vni);
|
|
|
|
if (!vnip)
|
|
|
|
return 0;
|
|
|
|
|
2019-09-06 06:11:07 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2019-09-06 06:11:07 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If the remote vtep entry doesn't exists nothing to do */
|
2020-08-10 18:40:48 +02:00
|
|
|
zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
|
2019-09-06 06:11:07 +02:00
|
|
|
if (!zvtep)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2020-10-21 19:57:06 +02:00
|
|
|
"Del MAC for remote VTEP %pI4 intf %s(%u) VNI %u - readd",
|
|
|
|
&vtep_ip, ifp->name, ifp->ifindex, vni);
|
2019-09-06 06:11:07 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_vtep_install(zevpn, zvtep);
|
2019-09-06 06:11:07 +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
|
|
|
*/
|
2020-05-09 03:47:52 +02:00
|
|
|
static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr,
|
2021-07-27 09:47:52 +02:00
|
|
|
vlanid_t vid, vni_t vni)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-05-15 07:44:13 +02:00
|
|
|
struct zebra_if *zif;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
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-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
2020-07-23 23:58:45 +02:00
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
2017-05-15 07:44:13 +02:00
|
|
|
if (!mac)
|
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +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-05-15 07:44:13 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
"Add/update remote MAC %pEA intf %s(%u) VNI %u flags 0x%x - del local",
|
|
|
|
macaddr, ifp->name, ifp->ifindex, vni, mac->flags);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* Remove MAC from BGP. */
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags,
|
|
|
|
false /* force */);
|
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)) {
|
2020-07-23 23:58:45 +02:00
|
|
|
zebra_evpn_mac_del(zevpn, mac);
|
2017-07-06 00:03:14 +02:00
|
|
|
} else {
|
2020-09-08 15:56:33 +02:00
|
|
|
zebra_evpn_mac_clear_fwd_info(mac);
|
2020-03-29 17:43:55 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
|
2019-05-09 21:25:44 +02:00
|
|
|
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
|
2017-07-06 00:03:14 +02:00
|
|
|
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 03:47:52 +02:00
|
|
|
/* MAC notification from the dataplane with a network dest port -
|
|
|
|
* 1. This can be a local MAC on a down ES (if fast-failover is not possible
|
|
|
|
* 2. Or it can be a remote MAC
|
|
|
|
*/
|
|
|
|
int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
|
|
|
struct ethaddr *macaddr, vlanid_t vid,
|
2021-07-27 09:47:52 +02:00
|
|
|
vni_t vni, uint32_t nhg_id, bool sticky,
|
|
|
|
bool dp_static)
|
2020-05-09 03:47:52 +02:00
|
|
|
{
|
|
|
|
struct zebra_evpn_es *es;
|
|
|
|
struct interface *acc_ifp;
|
|
|
|
|
zebra: fix bond down for evpn-mh
The test case is with `redirect-off` in evpn multi-homing environment:
```
evpn mh redirect-off
```
After the environment is setup, do the following steps:
1) Let one member of ES learn one mac:
```
2e:52:bb:bb:2f:46 dev ae1 vlan 100 master bridge0 static
```
Now everything is ok and the mac can be synced to other ES peers.
2) Shutdown bond1. At this time, zebra will get three netlink messages,
not one as current code expected. Like:
```
e4:f0:04:89:b6:46 dev vxlan10030 vlan 30 master bridge0 static <-A
e4:f0:04:89:b6:46 dev vxlan10030 nhid 536870913 self extern_learn <-B
e4:f0:04:89:b6:46 dev vxlan10030 vlan 30 self <-C
```
With A), zebra will wrongly remove this mac again:
```
ZEBRA: dpAdd remote MAC e4:f0:04:89:b6:46 VID 30
ZEBRA: Add/update remote MAC e4:f0:04:89:b6:46 intf vxlan10030(26) VNI 10030 flags 0xa01 - del local
ZEBRA: Send MACIP Del f None MAC e4:f0:04:89:b6:46 IP (null) seq 0 L2-VNI 10030 ESI - to bgp
```
With C), zebra will wrongly add this mac again:
```
ZEBRA: Rx RTM_NEWNEIGH AF_BRIDGE IF 26 VLAN 30 st 0x2 fl 0x2 MAC e4:f0:04:89:b6:46 nhg 0
ZEBRA: dpAdd remote MAC e4:f0:04:89:b6:46 VID 30
```
zebra should skip the two messages with `vid`. Otherwise, it will send many
*wrong* messages to bgpd, and the logic is wrong.
`nhg/dst` is in 2nd message without `vid`, it is useful to call
`zebra_evpn_add_update_local_mac()`. But it will fail with "could not find EVPN"
warning for no `vid`, can't call `zebra_evpn_add_update_local_mac()`:
With B):
```
ZEBRA: Rx RTM_NEWNEIGH AF_BRIDGE IF 26 st 0x2 fl 0x12 MAC e4:f0:04:89:b6:46 nhg 536870913
ZEBRA: dpAdd local-nw-MAC e4:f0:04:89:b6:46 VID 0
ZEBRA: Add/Update MAC e4:f0:04:89:b6:46 intf ae1(18) VID 0, could not find EVPN
```
Here, we can get `vid` from vxlan interface instead of from netlink message.
In summary, `zebra_vxlan_dp_network_mac_add()` will process the three messages
wrongly expecting only one messsage, so its logic is wrong. Just skip the two
unuseful messages with `vid`.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-08-01 09:30:07 +02:00
|
|
|
/* If netlink message is with vid, it will have no nexthop.
|
|
|
|
* So skip it.
|
|
|
|
*/
|
|
|
|
if (vid) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
|
|
|
|
zlog_debug("dpAdd MAC %pEA VID %u - ignore as no nhid",
|
|
|
|
macaddr, vid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get vxlan's vid for netlink message has no it. */
|
2022-08-31 18:35:57 +02:00
|
|
|
vid = ((struct zebra_if *)ifp->info)
|
|
|
|
->l2info.vxl.vni_info.vni.access_vlan;
|
zebra: fix bond down for evpn-mh
The test case is with `redirect-off` in evpn multi-homing environment:
```
evpn mh redirect-off
```
After the environment is setup, do the following steps:
1) Let one member of ES learn one mac:
```
2e:52:bb:bb:2f:46 dev ae1 vlan 100 master bridge0 static
```
Now everything is ok and the mac can be synced to other ES peers.
2) Shutdown bond1. At this time, zebra will get three netlink messages,
not one as current code expected. Like:
```
e4:f0:04:89:b6:46 dev vxlan10030 vlan 30 master bridge0 static <-A
e4:f0:04:89:b6:46 dev vxlan10030 nhid 536870913 self extern_learn <-B
e4:f0:04:89:b6:46 dev vxlan10030 vlan 30 self <-C
```
With A), zebra will wrongly remove this mac again:
```
ZEBRA: dpAdd remote MAC e4:f0:04:89:b6:46 VID 30
ZEBRA: Add/update remote MAC e4:f0:04:89:b6:46 intf vxlan10030(26) VNI 10030 flags 0xa01 - del local
ZEBRA: Send MACIP Del f None MAC e4:f0:04:89:b6:46 IP (null) seq 0 L2-VNI 10030 ESI - to bgp
```
With C), zebra will wrongly add this mac again:
```
ZEBRA: Rx RTM_NEWNEIGH AF_BRIDGE IF 26 VLAN 30 st 0x2 fl 0x2 MAC e4:f0:04:89:b6:46 nhg 0
ZEBRA: dpAdd remote MAC e4:f0:04:89:b6:46 VID 30
```
zebra should skip the two messages with `vid`. Otherwise, it will send many
*wrong* messages to bgpd, and the logic is wrong.
`nhg/dst` is in 2nd message without `vid`, it is useful to call
`zebra_evpn_add_update_local_mac()`. But it will fail with "could not find EVPN"
warning for no `vid`, can't call `zebra_evpn_add_update_local_mac()`:
With B):
```
ZEBRA: Rx RTM_NEWNEIGH AF_BRIDGE IF 26 st 0x2 fl 0x12 MAC e4:f0:04:89:b6:46 nhg 536870913
ZEBRA: dpAdd local-nw-MAC e4:f0:04:89:b6:46 VID 0
ZEBRA: Add/Update MAC e4:f0:04:89:b6:46 intf ae1(18) VID 0, could not find EVPN
```
Here, we can get `vid` from vxlan interface instead of from netlink message.
In summary, `zebra_vxlan_dp_network_mac_add()` will process the three messages
wrongly expecting only one messsage, so its logic is wrong. Just skip the two
unuseful messages with `vid`.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-08-01 09:30:07 +02:00
|
|
|
|
2020-05-09 03:47:52 +02:00
|
|
|
/* if remote mac delete the local entry */
|
|
|
|
if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
|
|
|
|
|| !zebra_evpn_es_local_mac_via_network_port(es)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
|
|
|
|
zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr,
|
|
|
|
vid);
|
2021-07-27 09:47:52 +02:00
|
|
|
return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr, vid,
|
|
|
|
vni);
|
2020-05-09 03:47:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If local MAC on a down local ES translate the network-mac-add
|
2022-08-09 02:47:37 +02:00
|
|
|
* to a local-active-mac-add
|
2020-05-09 03:47:52 +02:00
|
|
|
*/
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
|
|
|
|
zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid);
|
|
|
|
acc_ifp = es->zif->ifp;
|
|
|
|
return zebra_vxlan_local_mac_add_update(
|
|
|
|
acc_ifp, br_if, macaddr, vid, sticky,
|
|
|
|
false /* local_inactive */, dp_static);
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/*
|
2020-05-09 03:47:52 +02:00
|
|
|
* Handle network MAC delete by kernel -
|
|
|
|
* 1. readd the remote MAC if we have it
|
|
|
|
* 2. local MAC with does ES may also need to be re-installed
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2020-05-09 03:47:52 +02:00
|
|
|
int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
2021-07-27 09:47:52 +02:00
|
|
|
struct ethaddr *macaddr, vlanid_t vid,
|
|
|
|
vni_t vni)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-11-29 11:25:35 +01:00
|
|
|
struct zebra_if *zif = NULL;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
|
2017-09-18 23:45:34 +02:00
|
|
|
/* Check if EVPN is enabled. */
|
|
|
|
if (!is_evpn_enabled())
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-11-29 11:25:35 +01:00
|
|
|
/* check if this is a remote RMAC and readd simillar to remote macs */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni)
|
|
|
|
return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* Locate hash entry; it is expected to exist. */
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
2020-07-23 23:58:45 +02:00
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
2017-05-15 07:44:13 +02:00
|
|
|
if (!mac)
|
|
|
|
return 0;
|
|
|
|
|
2020-05-09 03:47:52 +02:00
|
|
|
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
|
|
|
|
/* If remote entry simply re-install */
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
|
|
|
|
zlog_debug(
|
|
|
|
"dpDel remote MAC %pEA intf %s(%u) VNI %u - readd",
|
|
|
|
macaddr, ifp->name, ifp->ifindex, vni);
|
|
|
|
zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
|
|
|
|
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && mac->es
|
|
|
|
&& zebra_evpn_es_local_mac_via_network_port(mac->es)) {
|
|
|
|
/* If local entry via nw-port call local-del which will
|
|
|
|
* re-install entry in the dataplane is needed
|
|
|
|
*/
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
|
|
|
|
zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr,
|
|
|
|
vni);
|
2020-08-05 16:13:55 +02:00
|
|
|
|
|
|
|
zebra_evpn_del_local_mac(zevpn, mac, false);
|
2020-05-09 03:47:52 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
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-05-15 07:44:13 +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
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-19 22:33:53 +02:00
|
|
|
struct zebra_mac *mac;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
|
|
|
* map to a VNI.
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_map_vlan(ifp, br_if, vid);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
|
|
|
"VNI %u hash %p doesn't have intf upon local MAC DEL",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, zevpn);
|
2017-05-15 07:38:26 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-05-09 03:47:52 +02:00
|
|
|
/* If entry doesn't exist, nothing to do. */
|
|
|
|
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
|
|
|
|
if (!mac)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Is it a local entry? */
|
|
|
|
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-05 16:13:55 +02:00
|
|
|
return zebra_evpn_del_local_mac(zevpn, mac, false);
|
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-05-15 07:44:13 +02:00
|
|
|
int zebra_vxlan_local_mac_add_update(struct interface *ifp,
|
|
|
|
struct interface *br_if,
|
2017-05-15 23:42:57 +02:00
|
|
|
struct ethaddr *macaddr, vlanid_t vid,
|
2020-03-29 17:43:55 +02:00
|
|
|
bool sticky, bool local_inactive,
|
|
|
|
bool dp_static)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2018-11-02 16:30:41 +01:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-12 14:01:22 +02:00
|
|
|
assert(ifp);
|
2020-08-11 14:39:25 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* We are interested in MACs only on ports or (port, VLAN) that
|
2020-07-23 23:51:10 +02:00
|
|
|
* map to an EVPN.
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_map_vlan(ifp, br_if, vid);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn) {
|
2017-05-15 07:44:13 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2017-05-15 23:42:57 +02:00
|
|
|
zlog_debug(
|
2021-03-12 02:44:45 +01:00
|
|
|
" Add/Update %sMAC %pEA intf %s(%u) VID %u, could not find EVPN",
|
|
|
|
sticky ? "sticky " : "", macaddr,
|
2017-05-15 07:44:13 +02:00
|
|
|
ifp->name, ifp->ifindex, vid);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn->vxlan_if) {
|
2019-03-08 16:46:55 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2020-03-24 17:38:20 +01:00
|
|
|
" VNI %u hash %p doesn't have intf upon local MAC ADD",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, zevpn);
|
2017-05-15 07:44:13 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-10-25 14:25:00 +02:00
|
|
|
zvrf = zebra_vrf_get_evpn();
|
2020-07-24 00:04:53 +02:00
|
|
|
return zebra_evpn_add_update_local_mac(zvrf, zevpn, ifp, macaddr, vid,
|
|
|
|
sticky, local_inactive,
|
2020-08-05 16:13:55 +02:00
|
|
|
dp_static, NULL);
|
2017-05-15 07:44:13 +02:00
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Handle message from client to delete a remote VTEP for an EVPN.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2021-04-20 15:14:46 +02:00
|
|
|
void zebra_vxlan_remote_vtep_del_zapi(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
2018-03-27 21:13:34 +02:00
|
|
|
unsigned short l = 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2021-04-20 15:14:46 +02:00
|
|
|
"%s: EVPN is not enabled yet we have received a VTEP DEL msg",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2021-04-20 15:14:46 +02:00
|
|
|
zlog_debug("Recv VTEP DEL zapi for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2019-05-01 21:29:24 +02:00
|
|
|
int flood_control __attribute__((unused));
|
2019-05-01 03:29:03 +02:00
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2017-05-15 07:38:26 +02:00
|
|
|
l += IPV4_MAX_BYTELEN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-01 03:29:03 +02:00
|
|
|
/* Flood control is intentionally ignored right now */
|
|
|
|
STREAM_GETL(s, flood_control);
|
|
|
|
l += 4;
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2021-04-20 15:14:46 +02:00
|
|
|
zlog_debug("Recv VTEP DEL %pI4 VNI %u from %s",
|
2020-10-21 19:57:06 +02:00
|
|
|
&vtep_ip, vni,
|
2017-05-15 07:38:26 +02:00
|
|
|
zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
/* Enqueue for processing */
|
|
|
|
zebra_rib_queue_evpn_rem_vtep_del(zvrf_id(zvrf), vni, vtep_ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to delete a remote VTEP for an EVPN.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_remote_vtep_del(vrf_id_t vrf_id, vni_t vni,
|
|
|
|
struct in_addr vtep_ip)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-08-19 22:13:39 +02:00
|
|
|
struct zebra_vtep *zvtep;
|
2021-04-20 15:14:46 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
zlog_debug("%s: Can't process vtep del: EVPN is not enabled",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(vrf_id);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
|
|
|
zlog_debug("Can't process VTEP DEL for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
|
|
|
if (!zevpn) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2021-04-20 15:14:46 +02:00
|
|
|
"Failed to locate VNI hash for remote VTEP DEL, VNI %u",
|
|
|
|
vni);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-20 11:46:28 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
ifp = zevpn->vxlan_if;
|
|
|
|
if (!ifp) {
|
|
|
|
zlog_debug(
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP DEL",
|
|
|
|
zevpn->vni, zevpn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
zif = ifp->info;
|
2017-07-20 11:46:28 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* 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 = zebra_evpn_vtep_find(zevpn, &vtep_ip);
|
|
|
|
if (!zvtep)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zebra_evpn_vtep_uninstall(zevpn, &vtep_ip);
|
|
|
|
zebra_evpn_vtep_del(zevpn, zvtep);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle message from client to add a remote VTEP for an EVPN.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_remote_vtep_add(vrf_id_t vrf_id, vni_t vni,
|
|
|
|
struct in_addr vtep_ip, int flood_control)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn;
|
2021-04-20 15:14:46 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
struct zebra_if *zif;
|
2021-08-19 22:13:39 +02:00
|
|
|
struct zebra_vtep *zvtep;
|
2021-04-20 15:14:46 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
if (!is_evpn_enabled()) {
|
|
|
|
zlog_debug("%s: EVPN not enabled: can't process a VTEP ADD",
|
|
|
|
__func__);
|
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
zvrf = zebra_vrf_lookup_by_id(vrf_id);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
|
|
|
zlog_debug("Can't process VTEP ADD for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Locate VNI hash entry - expected to exist. */
|
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
|
|
|
if (!zevpn) {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_VTEP_ADD_FAILED,
|
|
|
|
"Failed to locate EVPN hash upon remote VTEP ADD, VNI %u",
|
|
|
|
vni);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifp = zevpn->vxlan_if;
|
|
|
|
if (!ifp) {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_VTEP_ADD_FAILED,
|
|
|
|
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
|
|
|
|
zevpn->vni, zevpn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
|
|
|
|
if (zvtep) {
|
|
|
|
/* If the remote VTEP already exists check if
|
|
|
|
* the flood mode has changed
|
|
|
|
*/
|
|
|
|
if (zvtep->flood_control != flood_control) {
|
|
|
|
if (zvtep->flood_control == VXLAN_FLOOD_DISABLED)
|
|
|
|
/* old mode was head-end-replication but
|
|
|
|
* is no longer; get rid of the HER fdb
|
|
|
|
* entry installed before
|
|
|
|
*/
|
|
|
|
zebra_evpn_vtep_uninstall(zevpn, &vtep_ip);
|
|
|
|
zvtep->flood_control = flood_control;
|
|
|
|
zebra_evpn_vtep_install(zevpn, zvtep);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, flood_control);
|
|
|
|
if (zvtep)
|
|
|
|
zebra_evpn_vtep_install(zevpn, zvtep);
|
|
|
|
else
|
|
|
|
flog_err(EC_ZEBRA_VTEP_ADD_FAILED,
|
|
|
|
"Failed to add remote VTEP, VNI %u zevpn %p",
|
|
|
|
vni, zevpn);
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Handle message from client to add a remote VTEP for an EVPN.
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2021-04-20 15:14:46 +02:00
|
|
|
void zebra_vxlan_remote_vtep_add_zapi(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
2018-03-27 21:13:34 +02:00
|
|
|
unsigned short l = 0;
|
2017-05-15 07:38:26 +02:00
|
|
|
vni_t vni;
|
|
|
|
struct in_addr vtep_ip;
|
2019-03-19 18:37:22 +01:00
|
|
|
int flood_control;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
if (!is_evpn_enabled()) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2021-04-20 15:14:46 +02:00
|
|
|
"%s: EVPN not enabled yet we received a VTEP ADD zapi msg",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-10 14:51:34 +01:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2021-04-20 15:14:46 +02:00
|
|
|
zlog_debug("Recv VTEP ADD zapi for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-06 23:57:33 +01:00
|
|
|
while (l < hdr->length) {
|
2017-05-15 07:38:26 +02:00
|
|
|
/* Obtain each remote VTEP and process. */
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
2017-05-15 07:38:26 +02:00
|
|
|
l += 4;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
|
2019-03-19 18:37:22 +01:00
|
|
|
STREAM_GETL(s, flood_control);
|
2019-05-01 03:29:03 +02:00
|
|
|
l += IPV4_MAX_BYTELEN + 4;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2021-04-20 15:14:46 +02:00
|
|
|
zlog_debug("Recv VTEP ADD %pI4 VNI %u flood %d from %s",
|
|
|
|
&vtep_ip, vni, flood_control,
|
|
|
|
zebra_route_string(client->proto));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-20 15:14:46 +02:00
|
|
|
/* Enqueue for processing */
|
|
|
|
zebra_rib_queue_evpn_rem_vtep_add(zvrf_id(zvrf), vni, vtep_ip,
|
|
|
|
flood_control);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
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
|
|
|
|
*/
|
2021-04-20 15:14:46 +02:00
|
|
|
int zebra_vxlan_add_del_gw_macip(struct interface *ifp, const struct prefix *p,
|
2017-06-28 10:51:10 +02:00
|
|
|
int add)
|
|
|
|
{
|
|
|
|
struct ipaddr ip;
|
|
|
|
struct ethaddr macaddr;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&ip, 0, sizeof(ip));
|
|
|
|
memset(&macaddr, 0, sizeof(macaddr));
|
2017-06-28 10:51:10 +02:00
|
|
|
|
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) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("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);
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(svi_if,
|
|
|
|
svi_if_link);
|
2017-08-20 02:28:58 +02:00
|
|
|
}
|
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
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(svi_if, svi_if);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
} 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;
|
2018-04-11 14:02:34 +02:00
|
|
|
if (svi_if_zif) {
|
|
|
|
svi_if_link = if_lookup_by_index_per_ns(
|
2018-04-11 17:25:32 +02:00
|
|
|
zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
svi_if_zif->link_ifindex);
|
2018-04-11 14:02:34 +02:00
|
|
|
if (svi_if_link)
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, svi_if_link);
|
2018-04-11 14:02:34 +02:00
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, ifp);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-06-28 10:51:10 +02:00
|
|
|
return 0;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug("VNI %u hash %p doesn't have intf upon MACVLAN up",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-11-03 23:34:46 +01:00
|
|
|
/* VRR IP is advertised only if gw-macip-adv-enabled */
|
|
|
|
if (IS_ZEBRA_IF_MACVLAN(ifp)) {
|
|
|
|
if (!advertise_gw_macip_enabled(zevpn))
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* SVI IP is advertised if gw or svi macip-adv-enabled */
|
|
|
|
if (!advertise_svi_macip_enabled(zevpn)
|
|
|
|
&& !advertise_gw_macip_enabled(zevpn))
|
|
|
|
return 0;
|
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
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)
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_gw_macip_add(ifp, zevpn, &macaddr, &ip);
|
2017-06-28 10:51:10 +02:00
|
|
|
else
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_gw_macip_del(ifp, zevpn, &ip);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Handle SVI interface going down.
|
|
|
|
* SVI can be associated to either L3-VNI or L2-VNI.
|
|
|
|
* For L2-VNI: At this point, this is a NOP since
|
|
|
|
* the kernel deletes the neighbor entries on this SVI (if any).
|
2020-07-23 23:51:10 +02:00
|
|
|
* We only need to update the vrf corresponding to zevpn.
|
2017-10-08 03:49:27 +02:00
|
|
|
* For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete
|
|
|
|
* from bgp
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
|
|
|
int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni) {
|
|
|
|
|
|
|
|
/* process l3-vni down */
|
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
|
|
|
|
/* remove association with svi-if */
|
|
|
|
zl3vni->svi_if = NULL;
|
|
|
|
} else {
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2020-11-02 19:53:50 +01:00
|
|
|
/* Unlink the SVI from the access VLAN */
|
|
|
|
zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, false);
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* since we dont have svi corresponding to zevpn, we associate it
|
2017-10-08 03:49:27 +02:00
|
|
|
* to default vrf. Note: the corresponding neigh entries on the
|
|
|
|
* SVI would have already been deleted */
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, link_if);
|
2020-11-02 19:53:50 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (zevpn) {
|
2021-11-12 17:09:48 +01:00
|
|
|
/* remove from l3-vni list */
|
|
|
|
zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_delete(zl3vni->l2vnis, zevpn);
|
2021-11-03 01:57:07 +01:00
|
|
|
|
2021-01-11 09:14:05 +01:00
|
|
|
zevpn->svi_if = NULL;
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vrf_id = VRF_DEFAULT;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* update the tenant vrf in BGP */
|
2021-05-05 03:09:37 +02:00
|
|
|
if (if_is_operative(zevpn->vxlan_if))
|
|
|
|
zebra_evpn_send_add_to_client(zevpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-10-08 03:49:27 +02:00
|
|
|
* Handle SVI interface coming up.
|
|
|
|
* SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni
|
|
|
|
* vxlan intf).
|
|
|
|
* For L2-VNI: we need to install any remote neighbors entried (used for
|
2021-12-20 02:46:58 +01:00
|
|
|
* arp-suppression)
|
2017-10-08 03:49:27 +02:00
|
|
|
* For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI
|
2017-05-15 07:44:13 +02:00
|
|
|
*/
|
|
|
|
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
|
|
|
|
{
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni = zl3vni_from_svi(ifp, link_if);
|
|
|
|
if (zl3vni) {
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* associate with svi */
|
|
|
|
zl3vni->svi_if = ifp;
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* process oper-up */
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* process SVI up for l2-vni */
|
|
|
|
struct neigh_walk_ctx n_wctx;
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_from_svi(ifp, link_if);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn->vxlan_if) {
|
2018-08-16 22:10:32 +02:00
|
|
|
zlog_debug(
|
2018-06-19 20:29:05 +02:00
|
|
|
"VNI %u hash %p doesn't have intf upon SVI up",
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->vni, zevpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"SVI %s(%u) VNI %u VRF %s is UP, installing neighbors",
|
2020-07-23 23:51:10 +02:00
|
|
|
ifp->name, ifp->ifindex, zevpn->vni,
|
2021-10-22 00:17:40 +02:00
|
|
|
ifp->vrf->name);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* update the vrf information for l2-vni and inform bgp */
|
2021-01-11 09:14:05 +01:00
|
|
|
zevpn->svi_if = ifp;
|
2021-10-22 00:17:40 +02:00
|
|
|
zevpn->vrf_id = ifp->vrf->vrf_id;
|
2021-05-05 03:09:37 +02:00
|
|
|
|
2021-11-12 17:09:48 +01:00
|
|
|
zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
|
|
|
|
if (zl3vni)
|
|
|
|
listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
|
2021-11-03 01:57:07 +01:00
|
|
|
|
2021-05-05 03:09:37 +02:00
|
|
|
if (if_is_operative(zevpn->vxlan_if))
|
|
|
|
zebra_evpn_send_add_to_client(zevpn);
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* Install any remote neighbors for this VNI. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&n_wctx, 0, sizeof(n_wctx));
|
2020-07-23 23:51:10 +02:00
|
|
|
n_wctx.zevpn = zevpn;
|
2020-07-24 00:30:23 +02:00
|
|
|
hash_iterate(zevpn->neigh_table, zebra_evpn_install_neigh_hash,
|
2017-10-08 03:49:27 +02:00
|
|
|
&n_wctx);
|
2020-11-02 19:53:50 +01:00
|
|
|
|
|
|
|
/* Link the SVI from the access VLAN */
|
|
|
|
zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, true);
|
2022-05-28 09:10:51 +02:00
|
|
|
|
|
|
|
/* Update MACIP routes created by advertise-svi-ip */
|
|
|
|
if (advertise_svi_macip_enabled(zevpn)) {
|
|
|
|
zebra_evpn_del_macip_for_intf(ifp, zevpn);
|
|
|
|
zebra_evpn_add_macip_for_intf(ifp, zevpn);
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
2017-05-15 07:44:13 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-06 22:55:35 +02:00
|
|
|
/*
|
|
|
|
* Handle MAC-VLAN interface going down.
|
|
|
|
* L3VNI: When MAC-VLAN interface goes down,
|
|
|
|
* find its associated SVI and update type2/type-5 routes
|
|
|
|
* with SVI as RMAC
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_macvlan_down(struct interface *ifp)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2019-09-06 22:55:35 +02:00
|
|
|
struct zebra_if *zif, *link_zif;
|
|
|
|
struct interface *link_ifp, *link_if;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
link_ifp = zif->link;
|
2019-10-11 20:42:12 +02:00
|
|
|
if (!link_ifp) {
|
2021-10-14 18:11:15 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"macvlan parent link is not found. Parent index %d ifp %s",
|
|
|
|
zif->link_ifindex,
|
2021-10-22 00:17:40 +02:00
|
|
|
ifindex2ifname(zif->link_ifindex,
|
|
|
|
ifp->vrf->vrf_id));
|
2019-10-11 20:42:12 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-09-06 22:55:35 +02:00
|
|
|
link_zif = link_ifp->info;
|
|
|
|
assert(link_zif);
|
|
|
|
|
|
|
|
link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
link_zif->link_ifindex);
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_svi(link_ifp, link_if);
|
|
|
|
if (zl3vni) {
|
|
|
|
zl3vni->mac_vlan_if = NULL;
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle MAC-VLAN interface going up.
|
|
|
|
* L3VNI: When MAC-VLAN interface comes up,
|
|
|
|
* find its associated SVI and update type-2 routes
|
|
|
|
* with MAC-VLAN's MAC as RMAC and for type-5 routes
|
|
|
|
* use SVI's MAC as RMAC.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_macvlan_up(struct interface *ifp)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2019-09-06 22:55:35 +02:00
|
|
|
struct zebra_if *zif, *link_zif;
|
|
|
|
struct interface *link_ifp, *link_if;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
assert(zif);
|
|
|
|
link_ifp = zif->link;
|
|
|
|
link_zif = link_ifp->info;
|
|
|
|
assert(link_zif);
|
|
|
|
|
|
|
|
link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
|
|
|
|
link_zif->link_ifindex);
|
|
|
|
zl3vni = zl3vni_from_svi(link_ifp, link_if);
|
|
|
|
if (zl3vni) {
|
|
|
|
/* associate with macvlan (VRR) interface */
|
|
|
|
zl3vni->mac_vlan_if = ifp;
|
|
|
|
|
|
|
|
/* process oper-up */
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
|
2017-12-14 00:20:34 +01:00
|
|
|
char *err, int err_str_sz, int filter,
|
2018-02-06 23:28:22 +01:00
|
|
|
int add)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2019-03-06 19:10:02 +01:00
|
|
|
struct zebra_vrf *zvrf_evpn = NULL;
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-03-06 19:10:02 +01:00
|
|
|
zvrf_evpn = zebra_vrf_get_evpn();
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni,
|
|
|
|
add ? "ADD" : "DEL");
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
/* check if the vni is already present under zvrf */
|
|
|
|
if (zvrf->l3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz,
|
2017-10-08 03:49:27 +02:00
|
|
|
"VNI is already configured under the vrf");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if this VNI is already present in the system */
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (zl3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz,
|
2017-10-08 03:49:27 +02:00
|
|
|
"VNI is already configured as L3-VNI");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-05-19 03:55:33 +02:00
|
|
|
/* Remove L2VNI if present */
|
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* add the L3-VNI to the global table */
|
|
|
|
zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
|
|
|
|
|
|
|
|
/* associate the vrf with vni */
|
|
|
|
zvrf->l3vni = vni;
|
|
|
|
|
2018-02-06 23:28:22 +01:00
|
|
|
/* set the filter in l3vni to denote if we are using l3vni only
|
|
|
|
* for prefix routes
|
|
|
|
*/
|
|
|
|
if (filter)
|
|
|
|
SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* associate with vxlan-intf;
|
2017-12-27 20:47:10 +01:00
|
|
|
* we need to associate with the vxlan-intf first
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
|
|
|
|
|
|
|
|
/* associate with corresponding SVI interface, we can associate
|
|
|
|
* with svi-if only after vxlan interface association is
|
2017-12-27 20:47:10 +01:00
|
|
|
* complete
|
|
|
|
*/
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
|
|
|
|
|
2019-08-02 08:33:24 +02:00
|
|
|
zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: l3vni %u svi_if %s mac_vlan_if %s",
|
|
|
|
__func__, vni,
|
|
|
|
zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
|
|
|
|
zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name
|
|
|
|
: "NIL");
|
2019-08-02 08:33:24 +02:00
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
/* formulate l2vni list */
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf_evpn->evpn_table, zevpn_add_to_l3vni_list,
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni);
|
|
|
|
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
zl3vni = zl3vni_lookup(vni);
|
|
|
|
if (!zl3vni) {
|
2017-12-14 00:20:34 +01:00
|
|
|
snprintf(err, err_str_sz, "VNI doesn't exist");
|
2017-05-15 07:38:26 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
2019-04-11 21:04:34 +02:00
|
|
|
if (zvrf->l3vni != vni) {
|
|
|
|
snprintf(err, err_str_sz,
|
|
|
|
"VNI %d doesn't exist in VRF: %s",
|
|
|
|
vni, zvrf->vrf->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-04-10 10:37:21 +02:00
|
|
|
if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) {
|
|
|
|
snprintf(err, ERR_STR_SZ,
|
|
|
|
"prefix-routes-only is not set for the vni");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
|
|
|
|
2017-10-18 10:46:40 +02:00
|
|
|
/* delete and uninstall all rmacs */
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
|
|
|
|
/* delete and uninstall all next-hops */
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zvrf->l3vni = 0;
|
|
|
|
zl3vni_del(zl3vni);
|
|
|
|
|
2020-12-02 04:54:53 +01:00
|
|
|
/* Add L2VNI for this VNI */
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
zl3vni->vrf_id = zvrf_id(zvrf);
|
|
|
|
if (is_l3vni_oper_up(zl3vni))
|
|
|
|
zebra_vxlan_process_l3vni_oper_up(zl3vni);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
2017-10-08 03:49:27 +02:00
|
|
|
if (!zl3vni)
|
2017-05-15 07:38:26 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-10-08 03:49:27 +02:00
|
|
|
zebra_vxlan_process_l3vni_oper_down(zl3vni);
|
2020-07-06 20:13:54 +02:00
|
|
|
|
|
|
|
/* delete and uninstall all rmacs */
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, zl3vni);
|
|
|
|
/* delete and uninstall all next-hops */
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, zl3vni);
|
|
|
|
|
|
|
|
zl3vni->vrf_id = VRF_UNKNOWN;
|
|
|
|
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
vni_t vni;
|
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (!zl3vni)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
vni = zl3vni->vni;
|
2017-10-08 03:49:27 +02:00
|
|
|
zl3vni_del(zl3vni);
|
2023-05-28 17:31:23 +02:00
|
|
|
|
|
|
|
if (!zrouter.in_shutdown)
|
|
|
|
zebra_vxlan_handle_vni_transition(zvrf, vni, 0);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to specify the flooding mechanism for
|
|
|
|
* BUM packets. The default is to do head-end (ingress) replication
|
|
|
|
* and the other supported option is to disable it. This applies to
|
|
|
|
* all BUM traffic and disabling it applies to both the transmit and
|
|
|
|
* receive direction.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
enum vxlan_flood_control flood_ctrl;
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_err("EVPN flood control for non-EVPN VRF %u",
|
2018-10-05 00:42:57 +02:00
|
|
|
zvrf_id(zvrf));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETC(s, flood_ctrl);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("EVPN flood control %u, currently %u",
|
|
|
|
flood_ctrl, zvrf->vxlan_flood_ctrl);
|
|
|
|
|
|
|
|
if (zvrf->vxlan_flood_ctrl == flood_ctrl)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf->vxlan_flood_ctrl = flood_ctrl;
|
|
|
|
|
|
|
|
/* Install or uninstall flood entries corresponding to
|
|
|
|
* remote VTEPs.
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zebra_evpn_handle_flooding_remote_vteps,
|
2018-10-05 00:42:57 +02:00
|
|
|
zvrf);
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-05 17:38:35 +01:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of svi macip
|
|
|
|
* routes
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2019-02-05 17:38:35 +01:00
|
|
|
struct interface *ifp = NULL;
|
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-06-19 23:45:21 +02:00
|
|
|
zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u",
|
2019-02-21 18:08:36 +01:00
|
|
|
zvrf_id(zvrf));
|
2019-02-05 17:38:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = msg;
|
|
|
|
STREAM_GETC(s, advertise);
|
|
|
|
STREAM_GETL(s, vni);
|
|
|
|
|
|
|
|
if (!vni) {
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-06-19 23:45:21 +02:00
|
|
|
zlog_debug("EVPN SVI-MACIP Adv %s, currently %s",
|
2019-02-05 17:38:35 +01:00
|
|
|
advertise ? "enabled" : "disabled",
|
2019-08-08 19:43:49 +02:00
|
|
|
advertise_svi_macip_enabled(NULL)
|
2019-02-05 17:38:35 +01:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
if (zvrf->advertise_svi_macip == advertise)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (advertise) {
|
|
|
|
zvrf->advertise_svi_macip = advertise;
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_gw_macip_add_for_evpn_hash,
|
|
|
|
NULL);
|
2019-02-05 17:38:35 +01:00
|
|
|
} else {
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_svi_macip_del_for_evpn_hash,
|
|
|
|
NULL);
|
2019-02-05 17:38:35 +01:00
|
|
|
zvrf->advertise_svi_macip = advertise;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct interface *vlan_if = NULL;
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_vxlan_vni *zl2_info_vni;
|
2023-01-19 07:19:51 +01:00
|
|
|
int old_advertise;
|
2019-02-05 17:38:35 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2019-02-05 17:38:35 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2023-01-19 07:16:01 +01:00
|
|
|
"EVPN SVI macip Adv %s on VNI %d, currently %s",
|
2019-02-05 17:38:35 +01:00
|
|
|
advertise ? "enabled" : "disabled", vni,
|
2020-07-23 23:51:10 +02:00
|
|
|
advertise_svi_macip_enabled(zevpn)
|
2019-02-05 17:38:35 +01:00
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
2023-01-19 07:19:51 +01:00
|
|
|
old_advertise = advertise_svi_macip_enabled(zevpn);
|
2019-02-05 17:38:35 +01:00
|
|
|
|
2019-09-12 02:29:04 +02:00
|
|
|
/* Store flag even though SVI is not present.
|
|
|
|
* Once SVI comes up triggers self MAC-IP route add.
|
|
|
|
*/
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->advertise_svi_macip = advertise;
|
2023-01-19 07:19:51 +01:00
|
|
|
if (advertise_svi_macip_enabled(zevpn) == old_advertise)
|
|
|
|
return;
|
2019-09-12 02:29:04 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
ifp = zevpn->vxlan_if;
|
2019-02-05 17:38:35 +01:00
|
|
|
if (!ifp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
|
|
|
return;
|
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
|
|
|
|
if (!zl2_info_vni)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
|
2019-02-05 17:38:35 +01:00
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (advertise) {
|
|
|
|
/* Add primary SVI MAC-IP */
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
2019-02-05 17:38:35 +01:00
|
|
|
} else {
|
2019-09-12 02:29:04 +02:00
|
|
|
/* Del primary SVI MAC-IP */
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
|
2019-02-05 17:38:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-20 06:47:04 +01:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of g/w macip
|
|
|
|
* routes
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
|
2017-11-20 06:47:04 +01:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2017-11-20 06:47:04 +01:00
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct interface *vlan_if = NULL;
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_vxlan_vni *zl2_info_vni = NULL;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
|
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2018-04-27 15:21:28 +02:00
|
|
|
STREAM_GETC(s, advertise);
|
2020-01-13 22:22:27 +01:00
|
|
|
STREAM_GET(&vni, s, 3);
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (zevpn->advertise_subnet == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2023-01-19 07:16:01 +01:00
|
|
|
zlog_debug("EVPN subnet Adv %s on VNI %d, currently %s",
|
2017-11-20 06:47:04 +01:00
|
|
|
advertise ? "enabled" : "disabled", vni,
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->advertise_subnet ? "enabled" : "disabled");
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->advertise_subnet = advertise;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
ifp = zevpn->vxlan_if;
|
2017-11-20 06:47:04 +01:00
|
|
|
if (!ifp)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
|
|
|
zif = ifp->info;
|
|
|
|
|
|
|
|
/* If down or not mapped to a bridge, we're done. */
|
|
|
|
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
|
|
|
|
if (!zl2_info_vni)
|
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
|
|
|
|
zif->brslave_info.br_if);
|
2017-11-20 06:47:04 +01:00
|
|
|
if (!vlan_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (zevpn->advertise_subnet)
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_advertise_subnet(zevpn, vlan_if, 1);
|
2017-11-20 06:47:04 +01:00
|
|
|
else
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_advertise_subnet(zevpn, vlan_if, 0);
|
2018-04-27 15:21:28 +02:00
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
return;
|
2017-11-20 06:47:04 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
/*
|
|
|
|
* Handle message from client to enable/disable advertisement of g/w macip
|
|
|
|
* routes
|
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
|
2017-06-28 10:51:10 +02:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
int advertise;
|
|
|
|
vni_t vni = 0;
|
2021-08-19 22:08:53 +02:00
|
|
|
struct zebra_evpn *zevpn = NULL;
|
2017-07-20 11:46:28 +02:00
|
|
|
struct interface *ifp = NULL;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2019-03-27 02:13:16 +01:00
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-02-21 18:08:36 +01:00
|
|
|
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
|
2018-08-16 22:10:32 +02:00
|
|
|
zvrf_id(zvrf));
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
2018-03-02 02:18:34 +01:00
|
|
|
STREAM_GETL(s, vni);
|
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)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
zvrf->advertise_gw_macip = advertise;
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (advertise_gw_macip_enabled(zevpn))
|
|
|
|
hash_iterate(zvrf->evpn_table,
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_gw_macip_add_for_evpn_hash,
|
|
|
|
NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
else
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_gw_macip_del_for_evpn_hash,
|
|
|
|
NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
struct zebra_if *zif = NULL;
|
|
|
|
struct interface *vlan_if = NULL;
|
|
|
|
struct interface *vrr_if = NULL;
|
2021-07-27 09:44:15 +02:00
|
|
|
struct zebra_vxlan_vni *zl2_info_vni = NULL;
|
2023-01-19 07:19:51 +01:00
|
|
|
int old_advertise;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
zevpn = zebra_evpn_lookup(vni);
|
2020-07-23 23:51:10 +02:00
|
|
|
if (!zevpn)
|
2018-03-07 17:23:58 +01:00
|
|
|
return;
|
2017-12-13 21:18:11 +01:00
|
|
|
|
2017-06-28 10:51:10 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
2023-01-19 07:16:01 +01:00
|
|
|
"EVPN gateway macip Adv %s on VNI %d, currently %s",
|
2017-06-28 10:51:10 +02:00
|
|
|
advertise ? "enabled" : "disabled", vni,
|
2020-07-23 23:51:10 +02:00
|
|
|
advertise_gw_macip_enabled(zevpn) ? "enabled"
|
2023-01-19 07:16:01 +01:00
|
|
|
: "disabled");
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2023-01-19 07:19:51 +01:00
|
|
|
old_advertise = advertise_gw_macip_enabled(zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
zevpn->advertise_gw_macip = advertise;
|
2023-01-19 07:19:51 +01:00
|
|
|
if (advertise_gw_macip_enabled(zevpn) == old_advertise)
|
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
ifp = zevpn->vxlan_if;
|
2017-07-20 11:46:28 +02:00
|
|
|
if (!ifp)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
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)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-07-20 11:46:28 +02:00
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
|
|
|
|
if (!zl2_info_vni)
|
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2021-07-27 09:44:15 +02:00
|
|
|
vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
|
2017-06-28 10:51:10 +02:00
|
|
|
zif->brslave_info.br_if);
|
|
|
|
if (!vlan_if)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
if (advertise_gw_macip_enabled(zevpn)) {
|
2017-06-28 10:51:10 +02:00
|
|
|
/* Add primary SVI MAC-IP */
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* Add VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
} else {
|
|
|
|
/* Del primary MAC-IP */
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
|
|
|
/* Del VRR MAC-IP - if any*/
|
|
|
|
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
|
|
|
|
if (vrr_if)
|
2020-08-10 18:40:48 +02:00
|
|
|
zebra_evpn_del_macip_for_intf(vrr_if, zevpn);
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-06-28 10:51:10 +02:00
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
static int macfdb_read_ns(struct ns *ns,
|
|
|
|
void *_in_param __attribute__((unused)),
|
|
|
|
void **out_param __attribute__((unused)))
|
2019-09-27 15:46:22 +02:00
|
|
|
{
|
2019-12-20 17:51:37 +01:00
|
|
|
struct zebra_ns *zns = ns->info;
|
|
|
|
|
2019-09-27 15:46:22 +02:00
|
|
|
macfdb_read(zns);
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_CONTINUE;
|
2019-09-27 15:46:22 +02:00
|
|
|
}
|
|
|
|
|
2019-12-20 17:51:37 +01:00
|
|
|
static int neigh_read_ns(struct ns *ns,
|
|
|
|
void *_in_param __attribute__((unused)),
|
|
|
|
void **out_param __attribute__((unused)))
|
2019-09-27 15:46:22 +02:00
|
|
|
{
|
2019-12-20 17:51:37 +01:00
|
|
|
struct zebra_ns *zns = ns->info;
|
|
|
|
|
2019-09-27 15:46:22 +02:00
|
|
|
neigh_read(zns);
|
2019-12-20 17:51:37 +01:00
|
|
|
return NS_WALK_CONTINUE;
|
2019-09-27 15:46:22 +02:00
|
|
|
}
|
2017-06-28 10:51:10 +02:00
|
|
|
|
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.
|
2018-10-05 00:42:57 +02:00
|
|
|
* This also informs the setting for BUM handling at the time this change
|
|
|
|
* occurs; it is relevant only when specifying "learn".
|
2017-05-15 07:38:26 +02:00
|
|
|
*/
|
2018-03-06 23:57:33 +01:00
|
|
|
void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
|
2017-05-15 07:38:26 +02:00
|
|
|
{
|
2017-11-14 08:12:15 +01:00
|
|
|
struct stream *s = NULL;
|
|
|
|
int advertise = 0;
|
2018-10-05 00:42:57 +02:00
|
|
|
enum vxlan_flood_control flood_ctrl;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
2019-03-22 11:18:31 +01:00
|
|
|
/* Mismatch between EVPN VRF and current VRF (should be prevented by
|
|
|
|
* bgpd's cli) */
|
2019-03-22 13:37:06 +01:00
|
|
|
if (is_evpn_enabled() && !EVPN_ENABLED(zvrf))
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-09-18 23:45:34 +02:00
|
|
|
|
2018-03-07 00:08:37 +01:00
|
|
|
s = msg;
|
2017-11-10 14:51:34 +01:00
|
|
|
STREAM_GETC(s, advertise);
|
2018-10-05 00:42:57 +02:00
|
|
|
STREAM_GETC(s, flood_ctrl);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
2019-02-19 21:37:59 +01:00
|
|
|
zlog_debug("EVPN VRF %s(%u) VNI Adv %s, currently %s, flood control %u",
|
|
|
|
zvrf_name(zvrf), zvrf_id(zvrf),
|
2017-05-15 07:38:26 +02:00
|
|
|
advertise ? "enabled" : "disabled",
|
2018-10-05 00:42:57 +02:00
|
|
|
is_evpn_enabled() ? "enabled" : "disabled",
|
|
|
|
flood_ctrl);
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
if (zvrf->advertise_all_vni == advertise)
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
|
|
|
|
zvrf->advertise_all_vni = advertise;
|
2019-03-22 13:37:06 +01:00
|
|
|
if (EVPN_ENABLED(zvrf)) {
|
2019-03-27 02:16:27 +01:00
|
|
|
zrouter.evpn_vrf = zvrf;
|
2019-02-19 21:37:59 +01:00
|
|
|
|
2018-10-05 00:42:57 +02:00
|
|
|
/* Note BUM handling */
|
|
|
|
zvrf->vxlan_flood_ctrl = flood_ctrl;
|
|
|
|
|
2020-03-28 01:14:45 +01:00
|
|
|
/* Replay all ESs */
|
|
|
|
zebra_evpn_es_send_all_to_client(true /* add */);
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* Build EVPN hash table and inform BGP. */
|
|
|
|
zevpn_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*/
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table,
|
|
|
|
zebra_evpn_gw_macip_add_for_evpn_hash, NULL);
|
2017-06-28 10:51:10 +02:00
|
|
|
|
2017-05-15 07:44:13 +02:00
|
|
|
/* Read the MAC FDB */
|
2019-12-20 17:51:37 +01:00
|
|
|
ns_walk_func(macfdb_read_ns, NULL, NULL);
|
2017-05-15 07:44:13 +02:00
|
|
|
|
|
|
|
/* Read neighbors */
|
2019-12-20 17:51:37 +01:00
|
|
|
ns_walk_func(neigh_read_ns, NULL, NULL);
|
2017-05-15 07:38:26 +02:00
|
|
|
} else {
|
2020-07-23 23:51:10 +02:00
|
|
|
/* Cleanup VTEPs for all EVPNs - uninstall from
|
2017-05-15 07:38:26 +02:00
|
|
|
* kernel and free entries.
|
|
|
|
*/
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all,
|
|
|
|
zvrf);
|
2017-11-14 08:12:15 +01:00
|
|
|
|
2020-03-28 01:14:45 +01:00
|
|
|
/* Delete all ESs in BGP */
|
|
|
|
zebra_evpn_es_send_all_to_client(false /* add */);
|
|
|
|
|
2017-11-14 08:12:15 +01:00
|
|
|
/* cleanup all l3vnis */
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);
|
2019-02-19 21:37:59 +01:00
|
|
|
|
2019-03-27 02:16:27 +01:00
|
|
|
/* Mark as "no EVPN VRF" */
|
|
|
|
zrouter.evpn_vrf = NULL;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2017-11-10 14:51:34 +01:00
|
|
|
stream_failure:
|
2018-03-06 23:01:42 +01:00
|
|
|
return;
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-07-23 23:51:10 +02:00
|
|
|
* Allocate EVPN hash table for this VRF and do other initialization.
|
2017-05-15 07:38:26 +02:00
|
|
|
* NOTE: Currently supported only for default VRF.
|
|
|
|
*/
|
|
|
|
void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2021-04-26 15:34:41 +02:00
|
|
|
char buffer[80];
|
|
|
|
|
2017-05-15 07:38:26 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2021-04-26 15:34:41 +02:00
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "Zebra VRF EVPN Table: %s",
|
|
|
|
zvrf->vrf->name);
|
|
|
|
zvrf->evpn_table = hash_create_size(8, zebra_evpn_hash_keymake,
|
|
|
|
zebra_evpn_hash_cmp, buffer);
|
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "Zebra VxLAN SG Table: %s",
|
|
|
|
zvrf->vrf->name);
|
|
|
|
zvrf->vxlan_sg_table = hash_create_size(8, zebra_vxlan_sg_hash_key_make,
|
2021-05-09 19:37:12 +02:00
|
|
|
zebra_vxlan_sg_hash_eq, buffer);
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* Cleanup EVPN info, but don't free the table. */
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2020-03-28 01:14:45 +01:00
|
|
|
struct zebra_vrf *evpn_zvrf = zebra_vrf_get_evpn();
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
|
2020-06-28 17:56:03 +02:00
|
|
|
zebra_vxlan_cleanup_sg_table(zvrf);
|
2020-03-28 01:14:45 +01:00
|
|
|
|
|
|
|
if (zvrf == evpn_zvrf)
|
|
|
|
zebra_evpn_es_cleanup();
|
*: Handle VRF configuration when VRF gets inactivated and activated
A VRF is active only when the corresponding VRF device is present in the
kernel. However, when the kernel VRF device is removed, the VRF container in
FRR should go away only if there is no user configuration for it. Otherwise,
when the VRF device is created again so that the VRF becomes active, FRR
cannot take the correct actions. Example configuration for the VRF includes
static routes and EVPN L3 VNI.
Note that a VRF is currently considered to be "configured" as soon as the
operator has issued the "vrf <name>" command in FRR. Such a configured VRF
is not deleted upon VRF device removal, it is only made inactive. A VRF that
is "configured" can be deleted only upon operator action and only if the VRF
has been deactivated i.e., the VRF device removed from the kernel. This is
an existing restriction.
To implement this change, the VRF disable and delete actions have been modified.
Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Mitesh Kanjariya <mkanjariya@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
Ticket: CM-18553, CM-18918, CM-10139
Reviewed By: CCR-7022
Testing Done:
1. vrf and pim-vrf automation tests
2. Multiple VRF delete and readd (ifdown, ifup-with-depends)
3. FRR stop, start, restart
4. Networking restart
5. Configuration delete and readd
Some of the above tests run in different sequences (manually).
2017-12-02 02:36:37 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:51:10 +02:00
|
|
|
/* Close all EVPN handling */
|
2017-05-15 07:38:26 +02:00
|
|
|
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2017-09-18 23:45:34 +02:00
|
|
|
if (!zvrf)
|
|
|
|
return;
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
|
2020-07-23 23:51:10 +02:00
|
|
|
hash_free(zvrf->evpn_table);
|
2020-06-28 17:56:03 +02:00
|
|
|
if (zvrf->vxlan_sg_table) {
|
|
|
|
zebra_vxlan_cleanup_sg_table(zvrf);
|
|
|
|
hash_free(zvrf->vxlan_sg_table);
|
|
|
|
zvrf->vxlan_sg_table = NULL;
|
|
|
|
}
|
2017-05-15 07:38:26 +02:00
|
|
|
}
|
2017-10-08 03:49:27 +02:00
|
|
|
|
|
|
|
/* init the l3vni table */
|
2018-12-06 09:03:12 +01:00
|
|
|
void zebra_vxlan_init(void)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-08-27 16:43:37 +02:00
|
|
|
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
|
|
|
|
"Zebra VRF L3 VNI table");
|
2021-04-01 18:00:04 +02:00
|
|
|
|
|
|
|
svd_nh_table = zebra_neigh_db_create("Zebra SVD next-hop table");
|
|
|
|
|
2019-03-27 02:16:27 +01:00
|
|
|
zrouter.evpn_vrf = NULL;
|
2020-03-28 01:14:45 +01:00
|
|
|
zebra_evpn_mh_init();
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free l3vni table */
|
2018-12-06 09:03:12 +01:00
|
|
|
void zebra_vxlan_disable(void)
|
2017-10-08 03:49:27 +02:00
|
|
|
{
|
2018-08-27 16:43:37 +02:00
|
|
|
hash_free(zrouter.l3vni_table);
|
2020-03-28 01:14:45 +01:00
|
|
|
zebra_evpn_mh_terminate();
|
2017-10-08 03:49:27 +02:00
|
|
|
}
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
/* get the l3vni svi ifindex */
|
|
|
|
ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2017-10-11 10:32:54 +02:00
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return zl3vni->svi_if->ifindex;
|
|
|
|
}
|
2018-11-04 17:20:11 +01:00
|
|
|
|
2021-04-01 18:00:04 +02:00
|
|
|
/* get the l3vni vxlan ifindex */
|
|
|
|
ifindex_t get_l3vni_vxlan_ifindex(vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return zl3vni->vxlan_if->ifindex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the l3vni vni */
|
|
|
|
vni_t get_l3vni_vni(vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return zl3vni->vni;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is the vrf l3vni SVD backed? */
|
|
|
|
bool is_vrf_l3vni_svd_backed(vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
|
|
|
|
|
|
|
zl3vni = zl3vni_from_vrf(vrf_id);
|
|
|
|
if (!zl3vni || !is_l3vni_oper_up(zl3vni))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return IS_ZL3VNI_SVD_BACKED(zl3vni);
|
|
|
|
}
|
|
|
|
|
2019-03-19 21:15:23 +01:00
|
|
|
/************************** vxlan SG cache management ************************/
|
2019-03-19 21:56:46 +01:00
|
|
|
/* Inform PIM about the mcast group */
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg,
|
|
|
|
char *sg_str, uint16_t cmd)
|
2019-03-19 21:56:46 +01:00
|
|
|
{
|
|
|
|
struct zserv *client = NULL;
|
|
|
|
struct stream *s = NULL;
|
|
|
|
|
|
|
|
client = zserv_find_client(ZEBRA_ROUTE_PIM, 0);
|
|
|
|
if (!client)
|
|
|
|
return 0;
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG))
|
|
|
|
return 0;
|
|
|
|
|
2019-03-19 21:56:46 +01:00
|
|
|
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
|
|
|
|
|
|
|
zclient_create_header(s, cmd, VRF_DEFAULT);
|
|
|
|
stream_putl(s, IPV4_MAX_BYTELEN);
|
|
|
|
stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN);
|
|
|
|
stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN);
|
|
|
|
|
|
|
|
/* Write packet size. */
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug(
|
|
|
|
"Send %s %s to %s",
|
|
|
|
(cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", sg_str,
|
|
|
|
zebra_route_string(client->proto));
|
|
|
|
|
|
|
|
if (cmd == ZEBRA_VXLAN_SG_ADD)
|
|
|
|
client->vxlan_sg_add_cnt++;
|
|
|
|
else
|
|
|
|
client->vxlan_sg_del_cnt++;
|
|
|
|
|
|
|
|
return zserv_send_message(client, s);
|
|
|
|
}
|
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
const struct zebra_vxlan_sg *vxlan_sg = p;
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
return (jhash_2words(vxlan_sg->sg.src.s_addr,
|
|
|
|
vxlan_sg->sg.grp.s_addr, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2)
|
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
const struct zebra_vxlan_sg *sg1 = p1;
|
|
|
|
const struct zebra_vxlan_sg *sg2 = p2;
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr)
|
|
|
|
&& (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr));
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:53:44 +02:00
|
|
|
static struct zebra_vxlan_sg *zebra_vxlan_sg_new(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg;
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
vxlan_sg = XCALLOC(MTYPE_ZVXLAN_SG, sizeof(*vxlan_sg));
|
|
|
|
|
|
|
|
vxlan_sg->zvrf = zvrf;
|
|
|
|
vxlan_sg->sg = *sg;
|
|
|
|
prefix_sg2str(sg, vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
vxlan_sg = hash_get(zvrf->vxlan_sg_table, vxlan_sg, hash_alloc_intern);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("vxlan SG %s created", vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
return vxlan_sg;
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:53:44 +02:00
|
|
|
static struct zebra_vxlan_sg *zebra_vxlan_sg_find(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg lookup;
|
2019-03-19 21:15:23 +01:00
|
|
|
|
|
|
|
lookup.sg = *sg;
|
|
|
|
return hash_lookup(zvrf->vxlan_sg_table, &lookup);
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:53:44 +02:00
|
|
|
static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf,
|
|
|
|
struct prefix_sg *sg)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg;
|
|
|
|
struct zebra_vxlan_sg *parent = NULL;
|
2019-03-19 21:15:23 +01:00
|
|
|
struct in_addr sip;
|
|
|
|
|
|
|
|
vxlan_sg = zebra_vxlan_sg_find(zvrf, sg);
|
|
|
|
if (vxlan_sg)
|
|
|
|
return vxlan_sg;
|
|
|
|
|
|
|
|
/* create a *G entry for every BUM group implicitly -
|
|
|
|
* 1. The SG entry is used by pimd to setup the vxlan-origination-mroute
|
|
|
|
* 2. the XG entry is used by pimd to setup the
|
|
|
|
* vxlan-termination-mroute
|
|
|
|
*/
|
2020-02-06 07:49:02 +01:00
|
|
|
if (sg->src.s_addr != INADDR_ANY) {
|
2019-03-19 21:15:23 +01:00
|
|
|
memset(&sip, 0, sizeof(sip));
|
|
|
|
parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp);
|
|
|
|
if (!parent)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vxlan_sg = zebra_vxlan_sg_new(zvrf, sg);
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
zebra_vxlan_sg_send(zvrf, sg, vxlan_sg->sg_str,
|
|
|
|
ZEBRA_VXLAN_SG_ADD);
|
2019-03-19 21:56:46 +01:00
|
|
|
|
2019-03-19 21:15:23 +01:00
|
|
|
return vxlan_sg;
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:53:44 +02:00
|
|
|
static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
|
|
|
struct in_addr sip;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* On SG entry deletion remove the reference to its parent XG
|
|
|
|
* entry
|
|
|
|
*/
|
2020-02-06 07:49:02 +01:00
|
|
|
if (vxlan_sg->sg.src.s_addr != INADDR_ANY) {
|
2019-03-19 21:15:23 +01:00
|
|
|
memset(&sip, 0, sizeof(sip));
|
|
|
|
zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg,
|
|
|
|
vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL);
|
2019-03-19 21:56:46 +01:00
|
|
|
|
2019-03-19 21:15:23 +01:00
|
|
|
hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg);
|
|
|
|
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VXLAN SG %s deleted", vxlan_sg->sg_str);
|
|
|
|
|
|
|
|
XFREE(MTYPE_ZVXLAN_SG, vxlan_sg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip, struct in_addr mcast_grp)
|
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg;
|
2019-03-19 21:15:23 +01:00
|
|
|
struct prefix_sg sg;
|
|
|
|
|
|
|
|
sg.family = AF_INET;
|
|
|
|
sg.prefixlen = IPV4_MAX_BYTELEN;
|
|
|
|
sg.src = sip;
|
|
|
|
sg.grp = mcast_grp;
|
|
|
|
vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg);
|
|
|
|
if (!vxlan_sg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (vxlan_sg->ref_cnt)
|
|
|
|
--vxlan_sg->ref_cnt;
|
|
|
|
|
|
|
|
if (!vxlan_sg->ref_cnt)
|
|
|
|
zebra_vxlan_sg_del(vxlan_sg);
|
|
|
|
}
|
|
|
|
|
2021-08-20 14:53:44 +02:00
|
|
|
static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf,
|
|
|
|
struct in_addr sip,
|
|
|
|
struct in_addr mcast_grp)
|
2019-03-19 21:15:23 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg;
|
2019-03-19 21:15:23 +01:00
|
|
|
struct prefix_sg sg;
|
|
|
|
|
|
|
|
sg.family = AF_INET;
|
|
|
|
sg.prefixlen = IPV4_MAX_BYTELEN;
|
|
|
|
sg.src = sip;
|
|
|
|
sg.grp = mcast_grp;
|
|
|
|
vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg);
|
|
|
|
if (vxlan_sg)
|
|
|
|
++vxlan_sg->ref_cnt;
|
|
|
|
|
|
|
|
return vxlan_sg;
|
|
|
|
}
|
2019-03-19 21:26:22 +01:00
|
|
|
|
2021-07-27 09:47:52 +02:00
|
|
|
void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
|
|
|
|
struct in_addr mcast_grp)
|
2019-03-19 21:26:22 +01:00
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
2020-02-06 07:49:02 +01:00
|
|
|
if (local_vtep_ip.s_addr == INADDR_ANY
|
|
|
|
|| mcast_grp.s_addr == INADDR_ANY)
|
2019-03-19 21:26:22 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp);
|
|
|
|
}
|
|
|
|
|
2021-07-27 09:47:52 +02:00
|
|
|
void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp)
|
2019-03-19 21:26:22 +01:00
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
2020-02-06 07:49:02 +01:00
|
|
|
if (local_vtep_ip.s_addr == INADDR_ANY
|
|
|
|
|| mcast_grp.s_addr == INADDR_ANY)
|
2019-03-19 21:26:22 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
|
|
|
if (!zvrf)
|
|
|
|
return;
|
|
|
|
zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
|
|
|
|
}
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg)
|
2020-06-28 17:56:03 +02:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data;
|
2020-06-28 17:56:03 +02:00
|
|
|
|
|
|
|
/* increment the ref count against (*,G) to prevent them from being
|
|
|
|
* deleted
|
|
|
|
*/
|
|
|
|
if (vxlan_sg->sg.src.s_addr == INADDR_ANY)
|
|
|
|
++vxlan_sg->ref_cnt;
|
|
|
|
}
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *bucket, void *arg)
|
2020-06-28 17:56:03 +02:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data;
|
2020-06-28 17:56:03 +02:00
|
|
|
|
|
|
|
/* decrement the dummy ref count against (*,G) to delete them */
|
|
|
|
if (vxlan_sg->sg.src.s_addr == INADDR_ANY) {
|
|
|
|
if (vxlan_sg->ref_cnt)
|
|
|
|
--vxlan_sg->ref_cnt;
|
|
|
|
if (!vxlan_sg->ref_cnt)
|
|
|
|
zebra_vxlan_sg_del(vxlan_sg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
static void zebra_vxlan_sg_cleanup(struct hash_bucket *bucket, void *arg)
|
2019-03-19 21:26:22 +01:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data;
|
2019-03-19 21:26:22 +01:00
|
|
|
|
|
|
|
zebra_vxlan_sg_del(vxlan_sg);
|
|
|
|
}
|
2019-06-19 23:45:21 +02:00
|
|
|
|
2020-06-28 17:56:03 +02:00
|
|
|
static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf)
|
|
|
|
{
|
|
|
|
/* increment the ref count against (*,G) to prevent them from being
|
|
|
|
* deleted
|
|
|
|
*/
|
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_pre_cleanup, NULL);
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
|
|
|
|
|
|
|
|
/* decrement the dummy ref count against the XG entries */
|
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_post_cleanup, NULL);
|
|
|
|
}
|
|
|
|
|
2021-02-02 17:11:25 +01:00
|
|
|
static void zebra_vxlan_sg_replay_send(struct hash_bucket *bucket, void *arg)
|
2019-07-02 20:20:34 +02:00
|
|
|
{
|
2021-08-20 14:53:44 +02:00
|
|
|
struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data;
|
2019-07-02 20:20:34 +02:00
|
|
|
|
|
|
|
zebra_vxlan_sg_send(vxlan_sg->zvrf, &vxlan_sg->sg,
|
|
|
|
vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle message from client to replay vxlan SG entries */
|
|
|
|
void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG updates to PIM, start");
|
|
|
|
|
|
|
|
SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
|
|
|
|
|
|
|
|
if (!EVPN_ENABLED(zvrf)) {
|
2019-07-17 02:17:05 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG replay request on unexpected vrf %d",
|
|
|
|
zvrf->vrf->vrf_id);
|
2019-07-02 20:20:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_replay_send, NULL);
|
|
|
|
}
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
|
|
|
|
/* Cleanup EVPN configuration of a specific VRF */
|
|
|
|
static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf)
|
|
|
|
{
|
2021-08-20 14:58:24 +02:00
|
|
|
struct zebra_l3vni *zl3vni = NULL;
|
2019-06-28 19:42:08 +02:00
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
zvrf->advertise_all_vni = 0;
|
|
|
|
zvrf->advertise_gw_macip = 0;
|
|
|
|
zvrf->advertise_svi_macip = 0;
|
|
|
|
zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
|
|
|
|
|
2020-08-10 18:40:48 +02:00
|
|
|
hash_iterate(zvrf->evpn_table, zebra_evpn_cfg_cleanup, NULL);
|
2019-06-28 19:42:08 +02:00
|
|
|
|
|
|
|
if (zvrf->l3vni)
|
|
|
|
zl3vni = zl3vni_lookup(zvrf->l3vni);
|
|
|
|
if (zl3vni) {
|
|
|
|
/* delete and uninstall all rmacs */
|
|
|
|
hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
/* delete and uninstall all next-hops */
|
|
|
|
hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry,
|
|
|
|
zl3vni);
|
|
|
|
}
|
2019-06-19 23:45:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup BGP EVPN configuration upon client disconnect */
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_evpn_bgp_cfg_clean_up(struct zserv *client)
|
2019-06-19 23:45:21 +02:00
|
|
|
{
|
|
|
|
struct vrf *vrf;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
|
|
|
|
zvrf = vrf->info;
|
|
|
|
if (zvrf)
|
|
|
|
zebra_evpn_vrf_cfg_cleanup(zvrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
static int zebra_evpn_pim_cfg_clean_up(struct zserv *client)
|
|
|
|
{
|
|
|
|
struct zebra_vrf *zvrf = zebra_vrf_get_evpn();
|
|
|
|
|
2022-05-14 03:02:11 +02:00
|
|
|
if (CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) {
|
2019-07-02 20:20:34 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_VXLAN)
|
|
|
|
zlog_debug("VxLAN SG updates to PIM, stop");
|
|
|
|
UNSET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int zebra_evpn_cfg_clean_up(struct zserv *client)
|
|
|
|
{
|
|
|
|
if (client->proto == ZEBRA_ROUTE_BGP)
|
|
|
|
return zebra_evpn_bgp_cfg_clean_up(client);
|
|
|
|
|
|
|
|
if (client->proto == ZEBRA_ROUTE_PIM)
|
|
|
|
return zebra_evpn_pim_cfg_clean_up(client);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-30 17:54:07 +02:00
|
|
|
/*
|
|
|
|
* Handle results for vxlan dataplane operations.
|
|
|
|
*/
|
|
|
|
extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx)
|
|
|
|
{
|
2022-06-29 21:24:20 +02:00
|
|
|
return;
|
2019-07-30 17:54:07 +02:00
|
|
|
}
|
|
|
|
|
2021-07-06 16:59:35 +02:00
|
|
|
/* Config knob for accepting lower sequence numbers */
|
|
|
|
void zebra_vxlan_set_accept_bgp_seq(bool set)
|
|
|
|
{
|
|
|
|
accept_bgp_seq = set;
|
|
|
|
}
|
|
|
|
|
2022-11-01 19:09:15 +01:00
|
|
|
bool zebra_vxlan_get_accept_bgp_seq(void)
|
2021-07-06 16:59:35 +02:00
|
|
|
{
|
|
|
|
return accept_bgp_seq;
|
|
|
|
}
|
|
|
|
|
2019-06-19 23:45:21 +02:00
|
|
|
/* Cleanup BGP EVPN configuration upon client disconnect */
|
|
|
|
extern void zebra_evpn_init(void)
|
|
|
|
{
|
|
|
|
hook_register(zserv_client_close, zebra_evpn_cfg_clean_up);
|
|
|
|
}
|