summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/interface.c10
-rw-r--r--zebra/redistribute.c8
-rw-r--r--zebra/rt_netlink.c16
-rw-r--r--zebra/sample_plugin.c134
-rw-r--r--zebra/zebra_dplane.c4
-rw-r--r--zebra/zebra_fpm.c21
-rw-r--r--zebra/zebra_mpls.c40
-rw-r--r--zebra/zebra_nhg.c116
-rw-r--r--zebra/zebra_rib.c21
-rw-r--r--zebra/zebra_vrf.c27
-rw-r--r--zebra/zebra_vrf.h10
-rw-r--r--zebra/zebra_vty.c12
-rw-r--r--zebra/zebra_vxlan.c61
14 files changed, 370 insertions, 114 deletions
diff --git a/zebra/connected.c b/zebra/connected.c
index 75f4f53bc6..0ff474d787 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -65,7 +65,7 @@ static void connected_withdraw(struct connected *ifc)
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
listnode_delete(ifc->ifp->connected, ifc);
- connected_free(ifc);
+ connected_free(&ifc);
}
}
@@ -177,7 +177,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc)
*/
if (connected_same(current, ifc)) {
/* nothing to do */
- connected_free(ifc);
+ connected_free(&ifc);
return;
}
diff --git a/zebra/interface.c b/zebra/interface.c
index daa93e36d1..eea80652e5 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -738,7 +738,7 @@ static void if_delete_connected(struct interface *ifp)
ZEBRA_IFC_CONFIGURED)) {
listnode_delete(ifp->connected,
ifc);
- connected_free(ifc);
+ connected_free(&ifc);
} else
last = node;
}
@@ -759,7 +759,7 @@ static void if_delete_connected(struct interface *ifp)
last = node;
else {
listnode_delete(ifp->connected, ifc);
- connected_free(ifc);
+ connected_free(&ifc);
}
} else {
last = node;
@@ -829,7 +829,7 @@ void if_delete_update(struct interface *ifp)
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s is being deleted from the system",
ifp->name);
- if_delete(ifp);
+ if_delete(&ifp);
}
}
@@ -2878,7 +2878,7 @@ static int ip_address_uninstall(struct vty *vty, struct interface *ifp,
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
|| !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
listnode_delete(ifp->connected, ifc);
- connected_free(ifc);
+ connected_free(&ifc);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -3103,7 +3103,7 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp,
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
|| !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
listnode_delete(ifp->connected, ifc);
- connected_free(ifc);
+ connected_free(&ifc);
return CMD_WARNING_CONFIG_FAILED;
}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 4e0163f8ac..98603c9693 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -718,8 +718,8 @@ int zebra_import_table(afi_t afi, vrf_id_t vrf_id, uint32_t table_id,
if (afi >= AFI_MAX)
return (-1);
- table = zebra_vrf_table_with_table_id(afi, SAFI_UNICAST, vrf_id,
- table_id);
+ table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST, vrf_id,
+ table_id);
if (table == NULL) {
return 0;
} else if (IS_ZEBRA_DEBUG_RIB) {
@@ -830,8 +830,8 @@ static void zebra_import_table_rm_update_vrf_afi(struct zebra_vrf *zvrf,
if ((!rmap_name) || (strcmp(rmap_name, rmap) != 0))
return;
- table = zebra_vrf_table_with_table_id(afi, SAFI_UNICAST,
- zvrf->vrf->vrf_id, table_id);
+ table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST,
+ zvrf->vrf->vrf_id, table_id);
if (!table) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: Table id=%d not found", __func__,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 640802fe31..c9a9a81b18 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2246,6 +2246,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
enum nexthop_types_t type = 0;
int if_index = 0;
size_t sz = 0;
+ struct interface *ifp_lookup;
if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
@@ -2280,9 +2281,13 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
if (if_index)
nh.ifindex = if_index;
- *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
+ ifp_lookup =
+ if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
+
if (ifp)
- nh.vrf_id = (*ifp)->vrf_id;
+ *ifp = ifp_lookup;
+ if (ifp_lookup)
+ nh.vrf_id = ifp_lookup->vrf_id;
else {
flog_warn(
EC_ZEBRA_UNKNOWN_INTERFACE,
@@ -2451,7 +2456,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
return 0;
}
-#if 0 /* Force off kernel nexthop group installs for now */
/**
* netlink_request_nexthop() - Request nextop information from the kernel
* @zns: Zebra namespace
@@ -2510,12 +2514,6 @@ int netlink_nexthop_read(struct zebra_ns *zns)
return ret;
}
-#else
-int netlink_nexthop_read(struct zebra_ns *zns)
-{
- return 0;
-}
-#endif
int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
diff --git a/zebra/sample_plugin.c b/zebra/sample_plugin.c
new file mode 100644
index 0000000000..c96a86cc73
--- /dev/null
+++ b/zebra/sample_plugin.c
@@ -0,0 +1,134 @@
+/*
+ * Sample plugin for the FRR zebra dataplane.
+ *
+ * Copyright (c) 2019 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Should be possible to build this plugin using this sort of command:
+ *
+ * gcc -I ~/work/frr/ -I ~/work/frr/lib -I ~/work/frr/zebra \
+ * -g -O0 -o sample_plugin.so -shared -fPIC sample_plugin.c
+ *
+ * where 'frr' is a configured and built frr sandbox.
+ *
+ * Run zebra with '-M /path/to/sample_plugin.so' to load the module.
+ */
+
+#include "config.h" /* Include this explicitly */
+#include "lib/zebra.h"
+#include "lib/libfrr.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/debug.h"
+
+static const char *plugin_name = "SAMPLE";
+
+static struct zebra_dplane_provider *prov_p;
+
+/*
+ * Startup/init callback, called from the dataplane.
+ */
+static int sample_start(struct zebra_dplane_provider *prov)
+{
+ /* Nothing special to do - we don't allocate anything. */
+ return 0;
+}
+
+
+/*
+ * Shutdown/cleanup callback, called from the dataplane pthread.
+ */
+static int sample_fini(struct zebra_dplane_provider *prov, bool early)
+{
+ /* Nothing special to do. */
+ return 0;
+}
+
+/*
+ * Callback from the dataplane to process incoming work; this runs in the
+ * dplane pthread.
+ */
+static int sample_process(struct zebra_dplane_provider *prov)
+{
+ int counter, limit;
+ struct zebra_dplane_ctx *ctx;
+
+ limit = dplane_provider_get_work_limit(prov_p);
+
+ /* Respect the configured limit on the amount of work to do in
+ * any one call.
+ */
+ for (counter = 0; counter < limit; counter++) {
+ ctx = dplane_provider_dequeue_in_ctx(prov_p);
+ if (!ctx)
+ break;
+
+ /* Just set 'success' status and return to the dataplane */
+ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
+ dplane_provider_enqueue_out_ctx(prov_p, ctx);
+ }
+
+ return 0;
+}
+
+/*
+ * Init entry point called during zebra startup. This is registered during
+ * module init.
+ */
+static int init_sample_plugin(struct thread_master *tm)
+{
+ int ret;
+ struct zebra_dplane_provider *prov = NULL;
+
+ /* Note that we don't use or store the thread_master 'tm'. We
+ * don't use the zebra main pthread: our plugin code will run in
+ * the zebra dataplane pthread context.
+ */
+
+ /* Register the plugin with the dataplane infrastructure. We
+ * register to be called before the kernel, and we register
+ * our init, process work, and shutdown callbacks.
+ */
+ ret = dplane_provider_register(plugin_name, DPLANE_PRIO_PRE_KERNEL,
+ DPLANE_PROV_FLAGS_DEFAULT,
+ sample_start,
+ sample_process,
+ sample_fini,
+ NULL,
+ &prov_p);
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("sample plugin register => %d", ret);
+
+ return 0;
+}
+
+/*
+ * Base FRR loadable module info: basic info including module entry-point.
+ */
+static int module_init(void)
+{
+ hook_register(frr_late_init, init_sample_plugin);
+ return 0;
+}
+
+FRR_MODULE_SETUP(
+ .name = "dplane_sample",
+ .version = "0.0.1",
+ .description = "Dataplane Sample Plugin",
+ .init = module_init,
+ )
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index a88b0a38da..7f993442a6 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -3752,7 +3752,9 @@ void zebra_dplane_shutdown(void)
zdplane_info.dg_run = false;
- THREAD_OFF(zdplane_info.dg_t_update);
+ if (zdplane_info.dg_t_update)
+ thread_cancel_async(zdplane_info.dg_t_update->master,
+ &zdplane_info.dg_t_update, NULL);
frr_pthread_stop(zdplane_info.dg_pthread, NULL);
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 5d88d4eeb4..fa48c03c71 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -498,6 +498,11 @@ static inline void zfpm_write_off(void)
THREAD_WRITE_OFF(zfpm_g->t_write);
}
+static inline void zfpm_connect_off(void)
+{
+ THREAD_TIMER_OFF(zfpm_g->t_connect);
+}
+
/*
* zfpm_conn_up_thread_cb
*
@@ -731,7 +736,6 @@ static int zfpm_read_cb(struct thread *thread)
fpm_msg_hdr_t *hdr;
zfpm_g->stats.read_cb_calls++;
- zfpm_g->t_read = NULL;
/*
* Check if async connect is now done.
@@ -1157,7 +1161,6 @@ static int zfpm_write_cb(struct thread *thread)
int num_writes;
zfpm_g->stats.write_cb_calls++;
- zfpm_g->t_write = NULL;
/*
* Check if async connect is now done.
@@ -1241,7 +1244,6 @@ static int zfpm_connect_cb(struct thread *t)
int sock, ret;
struct sockaddr_in serv;
- zfpm_g->t_connect = NULL;
assert(zfpm_g->state == ZFPM_STATE_ACTIVE);
sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -2029,11 +2031,24 @@ static int zfpm_init(struct thread_master *master)
return 0;
}
+static int zfpm_fini(void)
+{
+ zfpm_write_off();
+ zfpm_read_off();
+ zfpm_connect_off();
+
+ zfpm_stop_stats_timer();
+
+ hook_unregister(rib_update, zfpm_trigger_update);
+ return 0;
+}
+
static int zebra_fpm_module_init(void)
{
hook_register(rib_update, zfpm_trigger_update);
hook_register(zebra_rmac_update, zfpm_trigger_rmac_update);
hook_register(frr_late_init, zfpm_init);
+ hook_register(frr_early_fini, zfpm_fini);
return 0;
}
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index ef1bd02608..6942a37989 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -2565,6 +2565,16 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
fec_print(rn->info, vty);
}
+static void mpls_zebra_nhg_update(struct route_entry *re, afi_t afi,
+ struct nexthop_group *new_grp)
+{
+ struct nhg_hash_entry *nhe;
+
+ nhe = zebra_nhg_rib_find(0, new_grp, afi);
+
+ zebra_nhg_re_update_ref(re, nhe);
+}
+
static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
enum lsp_types_t type, mpls_label_t label)
{
@@ -2591,7 +2601,6 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct route_entry *re;
struct nexthop *nexthop;
struct nexthop_group new_grp = {};
- struct nhg_hash_entry *nhe = NULL;
bool found;
afi_t afi = family2afi(prefix->family);
@@ -2658,12 +2667,11 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
}
if (found) {
- nhe = zebra_nhg_rib_find(0, &new_grp, afi);
-
- zebra_nhg_re_update_ref(re, nhe);
-
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+
+ mpls_zebra_nhg_update(re, afi, &new_grp);
+
rib_queue_add(rn);
}
@@ -2680,10 +2688,11 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
struct route_node *rn;
struct route_entry *re;
struct nexthop *nexthop;
+ struct nexthop_group new_grp = {};
+ afi_t afi = family2afi(prefix->family);
/* Lookup table. */
- table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
- zvrf_id(zvrf));
+ table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
if (!table)
return -1;
@@ -2698,11 +2707,18 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
if (re == NULL)
return -1;
- for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next)
+ nexthop_group_copy(&new_grp, re->ng);
+
+ for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next)
nexthop_del_labels(nexthop);
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+
+ mpls_zebra_nhg_update(re, afi, &new_grp);
+
+ nexthops_free(new_grp.nexthop);
+
rib_queue_add(rn);
return 0;
@@ -2904,7 +2920,6 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
update = 0;
RNODE_FOREACH_RE (rn, re) {
struct nexthop_group new_grp = {};
- struct nhg_hash_entry *nhe = NULL;
nexthop_group_copy(&new_grp, re->ng);
@@ -2920,11 +2935,8 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
update = 1;
}
- if (CHECK_FLAG(re->status,
- ROUTE_ENTRY_LABELS_CHANGED)) {
- nhe = zebra_nhg_rib_find(0, &new_grp, afi);
- zebra_nhg_re_update_ref(re, nhe);
- }
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
+ mpls_zebra_nhg_update(re, afi, &new_grp);
nexthops_free(new_grp.nexthop);
}
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 2bb117b272..2d7521d8be 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -360,6 +360,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
{
const struct nhg_hash_entry *nhe1 = arg1;
const struct nhg_hash_entry *nhe2 = arg2;
+ struct nexthop *nexthop1;
+ struct nexthop *nexthop2;
/* No matter what if they equal IDs, assume equal */
if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
@@ -371,12 +373,47 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
- if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
- != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
- return false;
+ /* Nexthops should be sorted */
+ for (nexthop1 = nhe1->nhg->nexthop, nexthop2 = nhe2->nhg->nexthop;
+ nexthop1 || nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+ if (nexthop1 && !nexthop2)
+ return false;
- if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg))
- return false;
+ if (!nexthop1 && nexthop2)
+ return false;
+
+ /*
+ * We have to check the active flag of each individual one,
+ * not just the overall active_num. This solves the special case
+ * issue of a route with a nexthop group with one nexthop
+ * resolving to itself and thus marking it inactive. If we
+ * have two different routes each wanting to mark a different
+ * nexthop inactive, they need to hash to two different groups.
+ *
+ * If we just hashed on num_active, they would hash the same
+ * which is incorrect.
+ *
+ * ex)
+ * 1.1.1.0/24
+ * -> 1.1.1.1 dummy1 (inactive)
+ * -> 1.1.2.1 dummy2
+ *
+ * 1.1.2.0/24
+ * -> 1.1.1.1 dummy1
+ * -> 1.1.2.1 dummy2 (inactive)
+ *
+ * Without checking each individual one, they would hash to
+ * the same group and both have 1.1.1.1 dummy1 marked inactive.
+ *
+ */
+ if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE)
+ != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
+ if (!nexthop_same(nexthop1, nexthop2))
+ return false;
+ }
return true;
}
@@ -552,20 +589,6 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
return nhe;
}
-static struct nhg_ctx *nhg_ctx_new()
-{
- struct nhg_ctx *new = NULL;
-
- new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
-
- return new;
-}
-
-static void nhg_ctx_free(struct nhg_ctx *ctx)
-{
- XFREE(MTYPE_NHG_CTX, ctx);
-}
-
static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
{
return ctx->id;
@@ -621,6 +644,36 @@ static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
return ctx->u.grp;
}
+static struct nhg_ctx *nhg_ctx_new()
+{
+ struct nhg_ctx *new = NULL;
+
+ new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
+
+ return new;
+}
+
+static void nhg_ctx_free(struct nhg_ctx **ctx)
+{
+ struct nexthop *nh;
+
+ if (ctx == NULL)
+ return;
+
+ assert((*ctx) != NULL);
+
+ if (nhg_ctx_get_count(*ctx))
+ goto done;
+
+ nh = nhg_ctx_get_nh(*ctx);
+
+ nexthop_del_labels(nh);
+
+done:
+ XFREE(MTYPE_NHG_CTX, *ctx);
+ *ctx = NULL;
+}
+
static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
struct nh_grp *grp, vrf_id_t vrf_id,
afi_t afi, int type, uint8_t count)
@@ -869,25 +922,14 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx)
return 0;
}
-static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
+static void nhg_ctx_fini(struct nhg_ctx **ctx)
{
- struct nexthop *nh;
-
/*
* Just freeing for now, maybe do something more in the future
* based on flag.
*/
- if (nhg_ctx_get_count(ctx))
- goto done;
-
- nh = nhg_ctx_get_nh(ctx);
-
- nexthop_del_labels(nh);
-
-done:
- if (ctx)
- nhg_ctx_free(ctx);
+ nhg_ctx_free(ctx);
}
static int queue_add(struct nhg_ctx *ctx)
@@ -942,7 +984,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx)
nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
- nhg_ctx_process_finish(ctx);
+ nhg_ctx_fini(&ctx);
return ret;
}
@@ -971,7 +1013,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
return nhg_ctx_process(ctx);
if (queue_add(ctx)) {
- nhg_ctx_process_finish(ctx);
+ nhg_ctx_fini(&ctx);
return -1;
}
@@ -988,7 +1030,7 @@ int zebra_nhg_kernel_del(uint32_t id)
nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
if (queue_add(ctx)) {
- nhg_ctx_process_finish(ctx);
+ nhg_ctx_fini(&ctx);
return -1;
}
@@ -1001,6 +1043,9 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
struct nexthop *lookup = NULL;
struct nhg_hash_entry *nhe = NULL;
+ if (!nh)
+ goto done;
+
copy_nexthops(&lookup, nh, NULL);
/* Clear it, in case its a group */
@@ -1013,6 +1058,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
nexthops_free(lookup);
+done:
return nhe;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index e0bf1a58f2..781963793e 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -570,14 +570,6 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
nexthops_free(old->fib_ng.nexthop);
old->fib_ng.nexthop = NULL;
}
-
- if (!RIB_SYSTEM_ROUTE(old)) {
- /* Clear old route's FIB flags */
- for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) {
- UNSET_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB);
- }
- }
}
if (zvrf)
@@ -1575,10 +1567,9 @@ rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx)
/* Locate rn and re(s) from ctx */
- table = zebra_vrf_table_with_table_id(dplane_ctx_get_afi(ctx),
- dplane_ctx_get_safi(ctx),
- dplane_ctx_get_vrf(ctx),
- dplane_ctx_get_table(ctx));
+ table = zebra_vrf_lookup_table_with_table_id(
+ dplane_ctx_get_afi(ctx), dplane_ctx_get_safi(ctx),
+ dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx));
if (table == NULL) {
if (IS_ZEBRA_DEBUG_DPLANE) {
zlog_debug("Failed to find route for ctx: no table for afi %d, safi %d, vrf %u",
@@ -2664,7 +2655,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
- table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
+ table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id,
+ re->table);
if (!table) {
if (re->ng)
nexthop_group_delete(&re->ng);
@@ -2809,7 +2801,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
- table = zebra_vrf_table_with_table_id(afi, safi, vrf_id, table_id);
+ table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id,
+ table_id);
if (!table)
return;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index f425c0e49e..c392303760 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -343,13 +343,12 @@ int zebra_vrf_has_config(struct zebra_vrf *zvrf)
* - case VRF backend is default : on default VRF only
* - case VRF backend is netns : on all VRFs
*/
-struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
- vrf_id_t vrf_id,
- uint32_t table_id)
+struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi,
+ vrf_id_t vrf_id,
+ uint32_t table_id)
{
struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
struct other_route_table ort, *otable;
- struct route_table *table;
if (!zvrf)
return NULL;
@@ -364,9 +363,28 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
ort.safi = safi;
ort.table_id = table_id;
otable = otable_find(&zvrf->other_tables, &ort);
+
if (otable)
return otable->table;
+ return NULL;
+}
+
+struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi,
+ vrf_id_t vrf_id,
+ uint32_t table_id)
+{
+ struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id);
+ struct other_route_table *otable;
+ struct route_table *table;
+
+ table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id,
+ table_id);
+
+ if (table)
+ goto done;
+
+ /* Create it as an `other` table */
table = zebra_router_get_table(zvrf, table_id, afi, safi);
otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable));
@@ -376,6 +394,7 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
otable->table = table;
otable_add(&zvrf->other_tables, otable);
+done:
return table;
}
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 6c80f9bcb4..5448e17073 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -233,9 +233,13 @@ zvrf_other_table_compare_func(const struct other_route_table *a,
DECLARE_RBTREE_UNIQ(otable, struct other_route_table, next,
zvrf_other_table_compare_func)
-struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
- vrf_id_t vrf_id,
- uint32_t table_id);
+extern struct route_table *
+zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id,
+ uint32_t table_id);
+extern struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi,
+ safi_t safi,
+ vrf_id_t vrf_id,
+ uint32_t table_id);
extern void zebra_vrf_update_all(struct zserv *client);
extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 9d17454730..12517f3135 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1708,10 +1708,9 @@ DEFPY (show_route_summary,
if ((zvrf = vrf->info) == NULL)
continue;
- table = zebra_vrf_table_with_table_id(afi,
- SAFI_UNICAST,
- zvrf->vrf->vrf_id,
- table_id);
+ table = zebra_vrf_lookup_table_with_table_id(
+ afi, SAFI_UNICAST, zvrf->vrf->vrf_id, table_id);
+
if (!table)
continue;
@@ -1726,9 +1725,8 @@ DEFPY (show_route_summary,
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
- table = zebra_vrf_table_with_table_id(afi,
- SAFI_UNICAST,
- vrf_id, table_id);
+ table = zebra_vrf_lookup_table_with_table_id(afi, SAFI_UNICAST,
+ vrf_id, table_id);
if (!table)
return CMD_SUCCESS;
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 2417b505ad..3efb407fae 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -4615,18 +4615,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
{
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
+ char buf2[PREFIX_STRLEN];
zebra_mac_t *zrmac = NULL;
zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
if (!zrmac) {
+ /* Create the RMAC entry, or update its vtep, if necessary. */
zrmac = zl3vni_rmac_add(zl3vni, rmac);
if (!zrmac) {
zlog_debug(
- "Failed to add RMAC %s L3VNI %u Remote VTEP %s",
+ "Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %s",
prefix_mac2str(rmac, buf, sizeof(buf)),
zl3vni->vni,
- ipaddr2str(vtep_ip, buf1, sizeof(buf1)));
+ ipaddr2str(vtep_ip, buf1, sizeof(buf1)),
+ prefix2str(host_prefix, buf2, sizeof(buf2)));
return -1;
}
memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
@@ -4638,6 +4641,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
/* 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(
+ "L3VNI %u Remote VTEP change(%s -> %s) for RMAC %s, prefix %s",
+ zl3vni->vni,
+ inet_ntoa(zrmac->fwd_info.r_vtep_ip),
+ ipaddr2str(vtep_ip, buf1, sizeof(buf1)),
+ prefix_mac2str(rmac, buf, sizeof(buf)),
+ prefix2str(host_prefix, buf2, sizeof(buf2)));
+
+ zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
+
+ /* install rmac in kernel */
+ zl3vni_rmac_install(zl3vni, zrmac);
}
rb_find_or_add_host(&zrmac->host_rb, host_prefix);
@@ -4786,24 +4804,39 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
struct prefix *host_prefix)
{
char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ char buf3[PREFIX_STRLEN];
zebra_neigh_t *nh = NULL;
+ /* Create the next hop entry, or update its mac, if necessary. */
nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
if (!nh) {
nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac);
if (!nh) {
-
zlog_debug(
- "Failed to add NH as Neigh (IP %s MAC %s L3-VNI %u)",
- ipaddr2str(vtep_ip, buf1, sizeof(buf1)),
+ "Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %s)",
+ ipaddr2str(vtep_ip, buf1, sizeof(buf2)),
prefix_mac2str(rmac, buf, sizeof(buf)),
- zl3vni->vni);
+ zl3vni->vni,
+ prefix2str(host_prefix, buf2, sizeof(buf2)));
return -1;
}
/* install the nh neigh in kernel */
zl3vni_nh_install(zl3vni, nh);
+ } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %s",
+ zl3vni->vni,
+ prefix_mac2str(&nh->emac, buf, sizeof(buf)),
+ prefix_mac2str(rmac, buf1, sizeof(buf1)),
+ ipaddr2str(vtep_ip, buf2, sizeof(buf2)),
+ prefix2str(host_prefix, buf3, sizeof(buf3)));
+
+ memcpy(&nh->emac, rmac, ETH_ALEN);
+ /* install (update) the nh neigh in kernel */
+ zl3vni_nh_install(zl3vni, nh);
}
rb_find_or_add_host(&nh->host_rb, host_prefix);
@@ -5775,12 +5808,14 @@ static void process_remote_macip_del(vni_t vni,
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
- __PRETTY_FUNCTION__,
- ipaddr2str(ipaddr, buf1,
- sizeof(buf1)), n->flags,
- vlan_if->name);
- neigh_read_specific_ip(ipaddr, vlan_if);
+ zlog_debug(
+ "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
+ __PRETTY_FUNCTION__,
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
+ n->flags,
+ vlan_if ? vlan_if->name : "Unknown");
+ if (vlan_if)
+ neigh_read_specific_ip(ipaddr, vlan_if);
}
/* When the MAC changes for an IP, it is possible the