summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/debug.c11
-rw-r--r--zebra/dplane_fpm_nl.c1162
-rw-r--r--zebra/if_netlink.c2
-rw-r--r--zebra/interface.c322
-rw-r--r--zebra/interface.h12
-rw-r--r--zebra/irdp_interface.c3
-rw-r--r--zebra/irdp_main.c5
-rw-r--r--zebra/kernel_netlink.c5
-rw-r--r--zebra/kernel_netlink.h2
-rw-r--r--zebra/label_manager.c177
-rw-r--r--zebra/label_manager.h55
-rw-r--r--zebra/main.c18
-rw-r--r--zebra/redistribute.c110
-rw-r--r--zebra/rib.h10
-rw-r--r--zebra/rt_netlink.c708
-rw-r--r--zebra/rt_netlink.h6
-rw-r--r--zebra/rtadv.c222
-rw-r--r--zebra/rtadv.h3
-rw-r--r--zebra/rule_netlink.c135
-rw-r--r--zebra/rule_socket.c8
-rw-r--r--zebra/subdir.am22
-rw-r--r--zebra/zapi_msg.c398
-rw-r--r--zebra/zapi_msg.h3
-rw-r--r--zebra/zebra_dplane.c280
-rw-r--r--zebra/zebra_dplane.h32
-rw-r--r--zebra/zebra_fpm.c72
-rw-r--r--zebra/zebra_fpm_protobuf.c2
-rw-r--r--zebra/zebra_mpls.c56
-rw-r--r--zebra/zebra_mpls.h4
-rw-r--r--zebra/zebra_mpls_vty.c10
-rw-r--r--zebra/zebra_nb.c692
-rw-r--r--zebra/zebra_nb.h488
-rw-r--r--zebra/zebra_nb_config.c1672
-rw-r--r--zebra/zebra_nb_rpcs.c212
-rw-r--r--zebra/zebra_nb_state.c637
-rw-r--r--zebra/zebra_netns_id.c2
-rw-r--r--zebra/zebra_nhg.c757
-rw-r--r--zebra/zebra_nhg.h39
-rw-r--r--zebra/zebra_ns.c1
-rw-r--r--zebra/zebra_pbr.c51
-rw-r--r--zebra/zebra_pbr.h7
-rw-r--r--zebra/zebra_pw.c9
-rw-r--r--zebra/zebra_rib.c533
-rw-r--r--zebra/zebra_routemap.c479
-rw-r--r--zebra/zebra_router.c7
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_snmp.c4
-rw-r--r--zebra/zebra_vrf.c2
-rw-r--r--zebra/zebra_vrf.h4
-rw-r--r--zebra/zebra_vty.c705
-rw-r--r--zebra/zebra_vxlan.c149
-rw-r--r--zebra/zebra_vxlan.h19
-rw-r--r--zebra/zebra_vxlan_private.h1
-rw-r--r--zebra/zserv.c60
-rw-r--r--zebra/zserv.h21
55 files changed, 8421 insertions, 1988 deletions
diff --git a/zebra/debug.c b/zebra/debug.c
index 68f6b69305..c920fca5ff 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -471,8 +471,13 @@ DEFPY (debug_zebra_nexthop,
}
/* Debug node. */
-struct cmd_node debug_node = {DEBUG_NODE, "", /* Debug node has no interface. */
- 1};
+static int config_write_debug(struct vty *vty);
+struct cmd_node debug_node = {
+ .name = "debug",
+ .node = DEBUG_NODE,
+ .prompt = "",
+ .config_write = config_write_debug,
+};
static int config_write_debug(struct vty *vty)
{
@@ -587,7 +592,7 @@ void zebra_debug_init(void)
zebra_debug_nht = 0;
zebra_debug_nexthop = 0;
- install_node(&debug_node, config_write_debug);
+ install_node(&debug_node);
install_element(VIEW_NODE, &show_debugging_zebra_cmd);
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
new file mode 100644
index 0000000000..9f480926ae
--- /dev/null
+++ b/zebra/dplane_fpm_nl.c
@@ -0,0 +1,1162 @@
+/*
+ * Zebra dataplane plugin for Forwarding Plane Manager (FPM) using netlink.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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
+ */
+
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "config.h" /* Include this explicitly */
+#include "lib/zebra.h"
+#include "lib/json.h"
+#include "lib/libfrr.h"
+#include "lib/frratomic.h"
+#include "lib/command.h"
+#include "lib/memory.h"
+#include "lib/network.h"
+#include "lib/ns.h"
+#include "lib/frr_pthread.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/kernel_netlink.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/debug.h"
+
+#define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK
+#define SOUTHBOUND_DEFAULT_PORT 2620
+
+/**
+ * FPM header:
+ * {
+ * version: 1 byte (always 1),
+ * type: 1 byte (1 for netlink, 2 protobuf),
+ * len: 2 bytes (network order),
+ * }
+ *
+ * This header is used with any format to tell the users how many bytes to
+ * expect.
+ */
+#define FPM_HEADER_SIZE 4
+
+static const char *prov_name = "dplane_fpm_nl";
+
+struct fpm_nl_ctx {
+ /* data plane connection. */
+ int socket;
+ bool disabled;
+ bool connecting;
+ bool rib_complete;
+ bool rmac_complete;
+ struct sockaddr_storage addr;
+
+ /* data plane buffers. */
+ struct stream *ibuf;
+ struct stream *obuf;
+ pthread_mutex_t obuf_mutex;
+
+ /*
+ * data plane context queue:
+ * When a FPM server connection becomes a bottleneck, we must keep the
+ * data plane contexts until we get a chance to process them.
+ */
+ struct dplane_ctx_q ctxqueue;
+ pthread_mutex_t ctxqueue_mutex;
+
+ /* data plane events. */
+ struct zebra_dplane_provider *prov;
+ struct frr_pthread *fthread;
+ struct thread *t_connect;
+ struct thread *t_read;
+ struct thread *t_write;
+ struct thread *t_event;
+ struct thread *t_dequeue;
+
+ /* zebra events. */
+ struct thread *t_ribreset;
+ struct thread *t_ribwalk;
+ struct thread *t_rmacreset;
+ struct thread *t_rmacwalk;
+
+ /* Statistic counters. */
+ struct {
+ /* Amount of bytes read into ibuf. */
+ _Atomic uint32_t bytes_read;
+ /* Amount of bytes written from obuf. */
+ _Atomic uint32_t bytes_sent;
+ /* Output buffer current usage. */
+ _Atomic uint32_t obuf_bytes;
+ /* Output buffer peak usage. */
+ _Atomic uint32_t obuf_peak;
+
+ /* Amount of connection closes. */
+ _Atomic uint32_t connection_closes;
+ /* Amount of connection errors. */
+ _Atomic uint32_t connection_errors;
+
+ /* Amount of user configurations: FNE_RECONNECT. */
+ _Atomic uint32_t user_configures;
+ /* Amount of user disable requests: FNE_DISABLE. */
+ _Atomic uint32_t user_disables;
+
+ /* Amount of data plane context processed. */
+ _Atomic uint32_t dplane_contexts;
+ /* Amount of data plane contexts enqueued. */
+ _Atomic uint32_t ctxqueue_len;
+ /* Peak amount of data plane contexts enqueued. */
+ _Atomic uint32_t ctxqueue_len_peak;
+
+ /* Amount of buffer full events. */
+ _Atomic uint32_t buffer_full;
+ } counters;
+} *gfnc;
+
+enum fpm_nl_events {
+ /* Ask for FPM to reconnect the external server. */
+ FNE_RECONNECT,
+ /* Disable FPM. */
+ FNE_DISABLE,
+ /* Reset counters. */
+ FNE_RESET_COUNTERS,
+};
+
+/*
+ * Prototypes.
+ */
+static int fpm_process_event(struct thread *t);
+static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx);
+static int fpm_rib_send(struct thread *t);
+static int fpm_rib_reset(struct thread *t);
+static int fpm_rmac_send(struct thread *t);
+static int fpm_rmac_reset(struct thread *t);
+
+/*
+ * Helper functions.
+ */
+
+/**
+ * Reorganizes the data on the buffer so it can fit more data.
+ *
+ * @param s stream pointer.
+ */
+static void stream_pulldown(struct stream *s)
+{
+ size_t rlen = STREAM_READABLE(s);
+
+ /* No more data, so just move the pointers. */
+ if (rlen == 0) {
+ stream_reset(s);
+ return;
+ }
+
+ /* Move the available data to the beginning. */
+ memmove(s->data, &s->data[s->getp], rlen);
+ s->getp = 0;
+ s->endp = rlen;
+}
+
+/*
+ * CLI.
+ */
+#define FPM_STR "Forwarding Plane Manager configuration\n"
+
+DEFUN(fpm_set_address, fpm_set_address_cmd,
+ "fpm address <A.B.C.D|X:X::X:X> [port (1-65535)]",
+ FPM_STR
+ "FPM remote listening server address\n"
+ "Remote IPv4 FPM server\n"
+ "Remote IPv6 FPM server\n"
+ "FPM remote listening server port\n"
+ "Remote FPM server port\n")
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ uint16_t port = 0;
+ uint8_t naddr[INET6_BUFSIZ];
+
+ if (argc == 5)
+ port = strtol(argv[4]->arg, NULL, 10);
+
+ /* Handle IPv4 addresses. */
+ if (inet_pton(AF_INET, argv[2]->arg, naddr) == 1) {
+ sin = (struct sockaddr_in *)&gfnc->addr;
+
+ memset(sin, 0, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_port =
+ port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ memcpy(&sin->sin_addr, naddr, sizeof(sin->sin_addr));
+
+ goto ask_reconnect;
+ }
+
+ /* Handle IPv6 addresses. */
+ if (inet_pton(AF_INET6, argv[2]->arg, naddr) != 1) {
+ vty_out(vty, "%% Invalid address: %s\n", argv[2]->arg);
+ return CMD_WARNING;
+ }
+
+ sin6 = (struct sockaddr_in6 *)&gfnc->addr;
+ memset(sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ memcpy(&sin6->sin6_addr, naddr, sizeof(sin6->sin6_addr));
+
+ask_reconnect:
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_RECONNECT, &gfnc->t_event);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_fpm_set_address, no_fpm_set_address_cmd,
+ "no fpm address [<A.B.C.D|X:X::X:X> [port <1-65535>]]",
+ NO_STR
+ FPM_STR
+ "FPM remote listening server address\n"
+ "Remote IPv4 FPM server\n"
+ "Remote IPv6 FPM server\n"
+ "FPM remote listening server port\n"
+ "Remote FPM server port\n")
+{
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_DISABLE, &gfnc->t_event);
+ return CMD_SUCCESS;
+}
+
+DEFUN(fpm_reset_counters, fpm_reset_counters_cmd,
+ "clear fpm counters",
+ CLEAR_STR
+ FPM_STR
+ "FPM statistic counters\n")
+{
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_RESET_COUNTERS, &gfnc->t_event);
+ return CMD_SUCCESS;
+}
+
+DEFUN(fpm_show_counters, fpm_show_counters_cmd,
+ "show fpm counters",
+ SHOW_STR
+ FPM_STR
+ "FPM statistic counters\n")
+{
+ vty_out(vty, "%30s\n%30s\n", "FPM counters", "============");
+
+#define SHOW_COUNTER(label, counter) \
+ vty_out(vty, "%28s: %u\n", (label), (counter))
+
+ SHOW_COUNTER("Input bytes", gfnc->counters.bytes_read);
+ SHOW_COUNTER("Output bytes", gfnc->counters.bytes_sent);
+ SHOW_COUNTER("Output buffer current size", gfnc->counters.obuf_bytes);
+ SHOW_COUNTER("Output buffer peak size", gfnc->counters.obuf_peak);
+ SHOW_COUNTER("Connection closes", gfnc->counters.connection_closes);
+ SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors);
+ SHOW_COUNTER("Data plane items processed",
+ gfnc->counters.dplane_contexts);
+ SHOW_COUNTER("Data plane items enqueued",
+ gfnc->counters.ctxqueue_len);
+ SHOW_COUNTER("Data plane items queue peak",
+ gfnc->counters.ctxqueue_len_peak);
+ SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full);
+ SHOW_COUNTER("User FPM configurations", gfnc->counters.user_configures);
+ SHOW_COUNTER("User FPM disable requests", gfnc->counters.user_disables);
+
+#undef SHOW_COUNTER
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd,
+ "show fpm counters json",
+ SHOW_STR
+ FPM_STR
+ "FPM statistic counters\n"
+ JSON_STR)
+{
+ struct json_object *jo;
+
+ jo = json_object_new_object();
+ json_object_int_add(jo, "bytes-read", gfnc->counters.bytes_read);
+ json_object_int_add(jo, "bytes-sent", gfnc->counters.bytes_sent);
+ json_object_int_add(jo, "obuf-bytes", gfnc->counters.obuf_bytes);
+ json_object_int_add(jo, "obuf-bytes-peak", gfnc->counters.obuf_peak);
+ json_object_int_add(jo, "connection-closes",
+ gfnc->counters.connection_closes);
+ json_object_int_add(jo, "connection-errors",
+ gfnc->counters.connection_errors);
+ json_object_int_add(jo, "data-plane-contexts",
+ gfnc->counters.dplane_contexts);
+ json_object_int_add(jo, "data-plane-contexts-queue",
+ gfnc->counters.ctxqueue_len);
+ json_object_int_add(jo, "data-plane-contexts-queue-peak",
+ gfnc->counters.ctxqueue_len_peak);
+ json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full);
+ json_object_int_add(jo, "user-configures",
+ gfnc->counters.user_configures);
+ json_object_int_add(jo, "user-disables", gfnc->counters.user_disables);
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
+ json_object_free(jo);
+
+ return CMD_SUCCESS;
+}
+
+static int fpm_write_config(struct vty *vty)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int written = 0;
+ char addrstr[INET6_ADDRSTRLEN];
+
+ if (gfnc->disabled)
+ return written;
+
+ switch (gfnc->addr.ss_family) {
+ case AF_INET:
+ written = 1;
+ sin = (struct sockaddr_in *)&gfnc->addr;
+ inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr));
+ vty_out(vty, "fpm address %s", addrstr);
+ if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT))
+ vty_out(vty, " port %d", ntohs(sin->sin_port));
+
+ vty_out(vty, "\n");
+ break;
+ case AF_INET6:
+ written = 1;
+ sin6 = (struct sockaddr_in6 *)&gfnc->addr;
+ inet_ntop(AF_INET, &sin6->sin6_addr, addrstr, sizeof(addrstr));
+ vty_out(vty, "fpm address %s", addrstr);
+ if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT))
+ vty_out(vty, " port %d", ntohs(sin6->sin6_port));
+
+ vty_out(vty, "\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return written;
+}
+
+static struct cmd_node fpm_node = {
+ .name = "fpm",
+ .node = FPM_NODE,
+ .prompt = "",
+ .config_write = fpm_write_config,
+};
+
+/*
+ * FPM functions.
+ */
+static int fpm_connect(struct thread *t);
+
+static void fpm_reconnect(struct fpm_nl_ctx *fnc)
+{
+ /* Grab the lock to empty the stream and stop the zebra thread. */
+ frr_mutex_lock_autounlock(&fnc->obuf_mutex);
+
+ /* Avoid calling close on `-1`. */
+ if (fnc->socket != -1) {
+ close(fnc->socket);
+ fnc->socket = -1;
+ }
+
+ stream_reset(fnc->ibuf);
+ stream_reset(fnc->obuf);
+ THREAD_OFF(fnc->t_read);
+ THREAD_OFF(fnc->t_write);
+
+ if (fnc->t_ribreset)
+ thread_cancel_async(zrouter.master, &fnc->t_ribreset, NULL);
+ if (fnc->t_ribwalk)
+ thread_cancel_async(zrouter.master, &fnc->t_ribwalk, NULL);
+ if (fnc->t_rmacreset)
+ thread_cancel_async(zrouter.master, &fnc->t_rmacreset, NULL);
+ if (fnc->t_rmacwalk)
+ thread_cancel_async(zrouter.master, &fnc->t_rmacwalk, NULL);
+
+ /* FPM is disabled, don't attempt to connect. */
+ if (fnc->disabled)
+ return;
+
+ thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3,
+ &fnc->t_connect);
+}
+
+static int fpm_read(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ ssize_t rv;
+
+ /* Let's ignore the input at the moment. */
+ rv = stream_read_try(fnc->ibuf, fnc->socket,
+ STREAM_WRITEABLE(fnc->ibuf));
+ if (rv == 0) {
+ atomic_fetch_add_explicit(&fnc->counters.connection_closes, 1,
+ memory_order_relaxed);
+
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: connection closed", __func__);
+
+ fpm_reconnect(fnc);
+ return 0;
+ }
+ if (rv == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK
+ || errno == EINTR)
+ return 0;
+
+ atomic_fetch_add_explicit(&fnc->counters.connection_errors, 1,
+ memory_order_relaxed);
+ zlog_warn("%s: connection failure: %s", __func__,
+ strerror(errno));
+ fpm_reconnect(fnc);
+ return 0;
+ }
+ stream_reset(fnc->ibuf);
+
+ /* Account all bytes read. */
+ atomic_fetch_add_explicit(&fnc->counters.bytes_read, rv,
+ memory_order_relaxed);
+
+ thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket,
+ &fnc->t_read);
+
+ return 0;
+}
+
+static int fpm_write(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ socklen_t statuslen;
+ ssize_t bwritten;
+ int rv, status;
+ size_t btotal;
+
+ if (fnc->connecting == true) {
+ status = 0;
+ statuslen = sizeof(status);
+
+ rv = getsockopt(fnc->socket, SOL_SOCKET, SO_ERROR, &status,
+ &statuslen);
+ if (rv == -1 || status != 0) {
+ if (rv != -1)
+ zlog_warn("%s: connection failed: %s", __func__,
+ strerror(status));
+ else
+ zlog_warn("%s: SO_ERROR failed: %s", __func__,
+ strerror(status));
+
+ atomic_fetch_add_explicit(
+ &fnc->counters.connection_errors, 1,
+ memory_order_relaxed);
+
+ fpm_reconnect(fnc);
+ return 0;
+ }
+
+ fnc->connecting = false;
+
+ /* Ask zebra main thread to start walking the RIB table. */
+ thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
+ &fnc->t_ribwalk);
+ thread_add_timer(zrouter.master, fpm_rmac_send, fnc, 0,
+ &fnc->t_rmacwalk);
+ }
+
+ frr_mutex_lock_autounlock(&fnc->obuf_mutex);
+
+ while (true) {
+ /* Stream is empty: reset pointers and return. */
+ if (STREAM_READABLE(fnc->obuf) == 0) {
+ stream_reset(fnc->obuf);
+ break;
+ }
+
+ /* Try to write all at once. */
+ btotal = stream_get_endp(fnc->obuf) -
+ stream_get_getp(fnc->obuf);
+ bwritten = write(fnc->socket, stream_pnt(fnc->obuf), btotal);
+ if (bwritten == 0) {
+ atomic_fetch_add_explicit(
+ &fnc->counters.connection_closes, 1,
+ memory_order_relaxed);
+
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: connection closed", __func__);
+ break;
+ }
+ if (bwritten == -1) {
+ /* Attempt to continue if blocked by a signal. */
+ if (errno == EINTR)
+ continue;
+ /* Receiver is probably slow, lets give it some time. */
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ atomic_fetch_add_explicit(
+ &fnc->counters.connection_errors, 1,
+ memory_order_relaxed);
+ zlog_warn("%s: connection failure: %s", __func__,
+ strerror(errno));
+ fpm_reconnect(fnc);
+ break;
+ }
+
+ /* Account all bytes sent. */
+ atomic_fetch_add_explicit(&fnc->counters.bytes_sent, bwritten,
+ memory_order_relaxed);
+
+ /* Account number of bytes free. */
+ atomic_fetch_sub_explicit(&fnc->counters.obuf_bytes, bwritten,
+ memory_order_relaxed);
+
+ stream_forward_getp(fnc->obuf, (size_t)bwritten);
+ }
+
+ /* Stream is not empty yet, we must schedule more writes. */
+ if (STREAM_READABLE(fnc->obuf)) {
+ stream_pulldown(fnc->obuf);
+ thread_add_write(fnc->fthread->master, fpm_write, fnc,
+ fnc->socket, &fnc->t_write);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int fpm_connect(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ struct sockaddr_in *sin = (struct sockaddr_in *)&fnc->addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&fnc->addr;
+ socklen_t slen;
+ int rv, sock;
+ char addrstr[INET6_ADDRSTRLEN];
+
+ sock = socket(fnc->addr.ss_family, SOCK_STREAM, 0);
+ if (sock == -1) {
+ zlog_err("%s: fpm socket failed: %s", __func__,
+ strerror(errno));
+ thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3,
+ &fnc->t_connect);
+ return 0;
+ }
+
+ set_nonblocking(sock);
+
+ if (fnc->addr.ss_family == AF_INET) {
+ inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr));
+ slen = sizeof(*sin);
+ } else {
+ inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr));
+ slen = sizeof(*sin6);
+ }
+
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: attempting to connect to %s:%d", __func__,
+ addrstr, ntohs(sin->sin_port));
+
+ rv = connect(sock, (struct sockaddr *)&fnc->addr, slen);
+ if (rv == -1 && errno != EINPROGRESS) {
+ atomic_fetch_add_explicit(&fnc->counters.connection_errors, 1,
+ memory_order_relaxed);
+ close(sock);
+ zlog_warn("%s: fpm connection failed: %s", __func__,
+ strerror(errno));
+ thread_add_timer(fnc->fthread->master, fpm_connect, fnc, 3,
+ &fnc->t_connect);
+ return 0;
+ }
+
+ fnc->connecting = (errno == EINPROGRESS);
+ fnc->socket = sock;
+ thread_add_read(fnc->fthread->master, fpm_read, fnc, sock,
+ &fnc->t_read);
+ thread_add_write(fnc->fthread->master, fpm_write, fnc, sock,
+ &fnc->t_write);
+
+ /* Mark all routes as unsent. */
+ thread_add_timer(zrouter.master, fpm_rib_reset, fnc, 0,
+ &fnc->t_ribreset);
+ thread_add_timer(zrouter.master, fpm_rmac_reset, fnc, 0,
+ &fnc->t_rmacreset);
+
+ return 0;
+}
+
+/**
+ * Encode data plane operation context into netlink and enqueue it in the FPM
+ * output buffer.
+ *
+ * @param fnc the netlink FPM context.
+ * @param ctx the data plane operation context data.
+ * @return 0 on success or -1 on not enough space.
+ */
+static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
+{
+ uint8_t nl_buf[NL_PKT_BUF_SIZE];
+ size_t nl_buf_len;
+ ssize_t rv;
+ uint64_t obytes, obytes_peak;
+
+ nl_buf_len = 0;
+
+ frr_mutex_lock_autounlock(&fnc->obuf_mutex);
+
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
+ rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf,
+ sizeof(nl_buf), true);
+ if (rv <= 0) {
+ zlog_err("%s: netlink_route_multipath failed",
+ __func__);
+ return 0;
+ }
+
+ nl_buf_len = (size_t)rv;
+
+ /* UPDATE operations need a INSTALL, otherwise just quit. */
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
+ break;
+
+ /* FALL THROUGH */
+ case DPLANE_OP_ROUTE_INSTALL:
+ rv = netlink_route_multipath(RTM_NEWROUTE, ctx,
+ &nl_buf[nl_buf_len],
+ sizeof(nl_buf) - nl_buf_len, true);
+ if (rv <= 0) {
+ zlog_err("%s: netlink_route_multipath failed",
+ __func__);
+ return 0;
+ }
+
+ nl_buf_len += (size_t)rv;
+ break;
+
+ case DPLANE_OP_MAC_INSTALL:
+ case DPLANE_OP_MAC_DELETE:
+ rv = netlink_macfdb_update_ctx(ctx, nl_buf, sizeof(nl_buf));
+ if (rv <= 0) {
+ zlog_err("%s: netlink_macfdb_update_ctx failed",
+ __func__);
+ return 0;
+ }
+
+ nl_buf_len = (size_t)rv;
+ break;
+
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ case DPLANE_OP_NH_DELETE:
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ case DPLANE_OP_ADDR_INSTALL:
+ case DPLANE_OP_ADDR_UNINSTALL:
+ case DPLANE_OP_NEIGH_INSTALL:
+ case DPLANE_OP_NEIGH_UPDATE:
+ case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_VTEP_ADD:
+ case DPLANE_OP_VTEP_DELETE:
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ case DPLANE_OP_SYS_ROUTE_DELETE:
+ case DPLANE_OP_ROUTE_NOTIFY:
+ case DPLANE_OP_LSP_NOTIFY:
+ case DPLANE_OP_NONE:
+ break;
+
+ default:
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: unhandled data plane message (%d) %s",
+ __func__, dplane_ctx_get_op(ctx),
+ dplane_op2str(dplane_ctx_get_op(ctx)));
+ break;
+ }
+
+ /* Skip empty enqueues. */
+ if (nl_buf_len == 0)
+ return 0;
+
+ /* We must know if someday a message goes beyond 65KiB. */
+ assert((nl_buf_len + FPM_HEADER_SIZE) <= UINT16_MAX);
+
+ /* Check if we have enough buffer space. */
+ if (STREAM_WRITEABLE(fnc->obuf) < (nl_buf_len + FPM_HEADER_SIZE)) {
+ atomic_fetch_add_explicit(&fnc->counters.buffer_full, 1,
+ memory_order_relaxed);
+
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug(
+ "%s: buffer full: wants to write %zu but has %zu",
+ __func__, nl_buf_len + FPM_HEADER_SIZE,
+ STREAM_WRITEABLE(fnc->obuf));
+
+ return -1;
+ }
+
+ /*
+ * Fill in the FPM header information.
+ *
+ * See FPM_HEADER_SIZE definition for more information.
+ */
+ stream_putc(fnc->obuf, 1);
+ stream_putc(fnc->obuf, 1);
+ stream_putw(fnc->obuf, nl_buf_len + FPM_HEADER_SIZE);
+
+ /* Write current data. */
+ stream_write(fnc->obuf, nl_buf, (size_t)nl_buf_len);
+
+ /* Account number of bytes waiting to be written. */
+ atomic_fetch_add_explicit(&fnc->counters.obuf_bytes,
+ nl_buf_len + FPM_HEADER_SIZE,
+ memory_order_relaxed);
+ obytes = atomic_load_explicit(&fnc->counters.obuf_bytes,
+ memory_order_relaxed);
+ obytes_peak = atomic_load_explicit(&fnc->counters.obuf_peak,
+ memory_order_relaxed);
+ if (obytes_peak < obytes)
+ atomic_store_explicit(&fnc->counters.obuf_peak, obytes,
+ memory_order_relaxed);
+
+ /* Tell the thread to start writing. */
+ thread_add_write(fnc->fthread->master, fpm_write, fnc, fnc->socket,
+ &fnc->t_write);
+
+ return 0;
+}
+
+/**
+ * Send all RIB installed routes to the connected data plane.
+ */
+static int fpm_rib_send(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ rib_dest_t *dest;
+ struct route_node *rn;
+ struct route_table *rt;
+ struct zebra_dplane_ctx *ctx;
+ rib_tables_iter_t rt_iter;
+
+ /* Allocate temporary context for all transactions. */
+ ctx = dplane_ctx_alloc();
+
+ rt_iter.state = RIB_TABLES_ITER_S_INIT;
+ while ((rt = rib_tables_iter_next(&rt_iter))) {
+ for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
+ dest = rib_dest_from_rnode(rn);
+ /* Skip bad route entries. */
+ if (dest == NULL || dest->selected_fib == NULL)
+ continue;
+
+ /* Check for already sent routes. */
+ if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_FPM))
+ continue;
+
+ /* Enqueue route install. */
+ dplane_ctx_reset(ctx);
+ dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_INSTALL, rn,
+ dest->selected_fib);
+ if (fpm_nl_enqueue(fnc, ctx) == -1) {
+ /* Free the temporary allocated context. */
+ dplane_ctx_fini(&ctx);
+
+ thread_add_timer(zrouter.master, fpm_rib_send,
+ fnc, 1, &fnc->t_ribwalk);
+ return 0;
+ }
+
+ /* Mark as sent. */
+ SET_FLAG(dest->flags, RIB_DEST_UPDATE_FPM);
+ }
+ }
+
+ /* Free the temporary allocated context. */
+ dplane_ctx_fini(&ctx);
+
+ /* All RIB routes sent! */
+ fnc->rib_complete = true;
+
+ return 0;
+}
+
+/*
+ * The next three functions will handle RMAC enqueue.
+ */
+struct fpm_rmac_arg {
+ struct zebra_dplane_ctx *ctx;
+ struct fpm_nl_ctx *fnc;
+ zebra_l3vni_t *zl3vni;
+};
+
+static void fpm_enqueue_rmac_table(struct hash_bucket *backet, void *arg)
+{
+ struct fpm_rmac_arg *fra = arg;
+ zebra_mac_t *zrmac = backet->data;
+ struct zebra_if *zif = fra->zl3vni->vxlan_if->info;
+ const struct zebra_l2info_vxlan *vxl = &zif->l2info.vxl;
+ struct zebra_if *br_zif;
+ vlanid_t vid;
+ bool sticky;
+
+ /* Entry already sent. */
+ if (CHECK_FLAG(zrmac->flags, ZEBRA_MAC_FPM_SENT))
+ return;
+
+ sticky = !!CHECK_FLAG(zrmac->flags,
+ (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
+ br_zif = (struct zebra_if *)(zif->brslave_info.br_if->info);
+ vid = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) ? vxl->access_vlan : 0;
+
+ dplane_ctx_reset(fra->ctx);
+ dplane_ctx_set_op(fra->ctx, DPLANE_OP_MAC_INSTALL);
+ dplane_mac_init(fra->ctx, fra->zl3vni->vxlan_if,
+ zif->brslave_info.br_if, vid,
+ &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, sticky);
+ if (fpm_nl_enqueue(fra->fnc, fra->ctx) == -1) {
+ thread_add_timer(zrouter.master, fpm_rmac_send,
+ fra->fnc, 1, &fra->fnc->t_rmacwalk);
+ }
+}
+
+static void fpm_enqueue_l3vni_table(struct hash_bucket *backet, void *arg)
+{
+ struct fpm_rmac_arg *fra = arg;
+ zebra_l3vni_t *zl3vni = backet->data;
+
+ fra->zl3vni = zl3vni;
+ hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni);
+}
+
+static int fpm_rmac_send(struct thread *t)
+{
+ struct fpm_rmac_arg fra;
+
+ fra.fnc = THREAD_ARG(t);
+ fra.ctx = dplane_ctx_alloc();
+ hash_iterate(zrouter.l3vni_table, fpm_enqueue_l3vni_table, &fra);
+ dplane_ctx_fini(&fra.ctx);
+
+ return 0;
+}
+
+/**
+ * Resets the RIB FPM flags so we send all routes again.
+ */
+static int fpm_rib_reset(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ rib_dest_t *dest;
+ struct route_node *rn;
+ struct route_table *rt;
+ rib_tables_iter_t rt_iter;
+
+ fnc->rib_complete = false;
+
+ rt_iter.state = RIB_TABLES_ITER_S_INIT;
+ while ((rt = rib_tables_iter_next(&rt_iter))) {
+ for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
+ dest = rib_dest_from_rnode(rn);
+ /* Skip bad route entries. */
+ if (dest == NULL)
+ continue;
+
+ UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_FPM);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The next three function will handle RMAC table reset.
+ */
+static void fpm_unset_rmac_table(struct hash_bucket *backet, void *arg)
+{
+ zebra_mac_t *zrmac = backet->data;
+
+ UNSET_FLAG(zrmac->flags, ZEBRA_MAC_FPM_SENT);
+}
+
+static void fpm_unset_l3vni_table(struct hash_bucket *backet, void *arg)
+{
+ zebra_l3vni_t *zl3vni = backet->data;
+
+ hash_iterate(zl3vni->rmac_table, fpm_unset_rmac_table, zl3vni);
+}
+
+static int fpm_rmac_reset(struct thread *t)
+{
+ hash_iterate(zrouter.l3vni_table, fpm_unset_l3vni_table, NULL);
+
+ return 0;
+}
+
+static int fpm_process_queue(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ struct zebra_dplane_ctx *ctx;
+
+ frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
+
+ while (true) {
+ /* No space available yet. */
+ if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE)
+ break;
+
+ /* Dequeue next item or quit processing. */
+ ctx = dplane_ctx_dequeue(&fnc->ctxqueue);
+ if (ctx == NULL)
+ break;
+
+ fpm_nl_enqueue(fnc, ctx);
+
+ /* Account the processed entries. */
+ atomic_fetch_add_explicit(&fnc->counters.dplane_contexts, 1,
+ memory_order_relaxed);
+ atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1,
+ memory_order_relaxed);
+
+ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
+ dplane_provider_enqueue_out_ctx(fnc->prov, ctx);
+ }
+
+ /* Check for more items in the queue. */
+ if (atomic_load_explicit(&fnc->counters.ctxqueue_len,
+ memory_order_relaxed)
+ > 0)
+ thread_add_timer(fnc->fthread->master, fpm_process_queue,
+ fnc, 0, &fnc->t_dequeue);
+
+ return 0;
+}
+
+/**
+ * Handles external (e.g. CLI, data plane or others) events.
+ */
+static int fpm_process_event(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ int event = THREAD_VAL(t);
+
+ switch (event) {
+ case FNE_DISABLE:
+ zlog_info("%s: manual FPM disable event", __func__);
+ fnc->disabled = true;
+ atomic_fetch_add_explicit(&fnc->counters.user_disables, 1,
+ memory_order_relaxed);
+
+ /* Call reconnect to disable timers and clean up context. */
+ fpm_reconnect(fnc);
+ break;
+
+ case FNE_RECONNECT:
+ zlog_info("%s: manual FPM reconnect event", __func__);
+ fnc->disabled = false;
+ atomic_fetch_add_explicit(&fnc->counters.user_configures, 1,
+ memory_order_relaxed);
+ fpm_reconnect(fnc);
+ break;
+
+ case FNE_RESET_COUNTERS:
+ zlog_info("%s: manual FPM counters reset event", __func__);
+ memset(&fnc->counters, 0, sizeof(fnc->counters));
+ break;
+
+ default:
+ if (IS_ZEBRA_DEBUG_FPM)
+ zlog_debug("%s: unhandled event %d", __func__, event);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Data plane functions.
+ */
+static int fpm_nl_start(struct zebra_dplane_provider *prov)
+{
+ struct fpm_nl_ctx *fnc;
+
+ fnc = dplane_provider_get_data(prov);
+ fnc->fthread = frr_pthread_new(NULL, prov_name, prov_name);
+ assert(frr_pthread_run(fnc->fthread, NULL) == 0);
+ fnc->ibuf = stream_new(NL_PKT_BUF_SIZE);
+ fnc->obuf = stream_new(NL_PKT_BUF_SIZE * 128);
+ pthread_mutex_init(&fnc->obuf_mutex, NULL);
+ fnc->socket = -1;
+ fnc->disabled = true;
+ fnc->prov = prov;
+ TAILQ_INIT(&fnc->ctxqueue);
+ pthread_mutex_init(&fnc->ctxqueue_mutex, NULL);
+
+ return 0;
+}
+
+static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
+{
+ /* Disable all events and close socket. */
+ THREAD_OFF(fnc->t_ribreset);
+ THREAD_OFF(fnc->t_ribwalk);
+ THREAD_OFF(fnc->t_rmacreset);
+ THREAD_OFF(fnc->t_rmacwalk);
+ thread_cancel_async(fnc->fthread->master, &fnc->t_read, NULL);
+ thread_cancel_async(fnc->fthread->master, &fnc->t_write, NULL);
+ thread_cancel_async(fnc->fthread->master, &fnc->t_connect, NULL);
+
+ if (fnc->socket != -1) {
+ close(fnc->socket);
+ fnc->socket = -1;
+ }
+
+ return 0;
+}
+
+static int fpm_nl_finish_late(struct fpm_nl_ctx *fnc)
+{
+ /* Stop the running thread. */
+ frr_pthread_stop(fnc->fthread, NULL);
+
+ /* Free all allocated resources. */
+ pthread_mutex_destroy(&fnc->obuf_mutex);
+ pthread_mutex_destroy(&fnc->ctxqueue_mutex);
+ stream_free(fnc->ibuf);
+ stream_free(fnc->obuf);
+ free(gfnc);
+ gfnc = NULL;
+
+ return 0;
+}
+
+static int fpm_nl_finish(struct zebra_dplane_provider *prov, bool early)
+{
+ struct fpm_nl_ctx *fnc;
+
+ fnc = dplane_provider_get_data(prov);
+ if (early)
+ return fpm_nl_finish_early(fnc);
+
+ return fpm_nl_finish_late(fnc);
+}
+
+static int fpm_nl_process(struct zebra_dplane_provider *prov)
+{
+ struct zebra_dplane_ctx *ctx;
+ struct fpm_nl_ctx *fnc;
+ int counter, limit;
+ uint64_t cur_queue, peak_queue;
+
+ fnc = dplane_provider_get_data(prov);
+ limit = dplane_provider_get_work_limit(prov);
+ for (counter = 0; counter < limit; counter++) {
+ ctx = dplane_provider_dequeue_in_ctx(prov);
+ if (ctx == NULL)
+ break;
+
+ /*
+ * Skip all notifications if not connected, we'll walk the RIB
+ * anyway.
+ */
+ if (fnc->socket != -1 && fnc->connecting == false) {
+ frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
+ dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx);
+
+ /* Account the number of contexts. */
+ atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len,
+ 1, memory_order_relaxed);
+ cur_queue = atomic_load_explicit(
+ &fnc->counters.ctxqueue_len,
+ memory_order_relaxed);
+ peak_queue = atomic_load_explicit(
+ &fnc->counters.ctxqueue_len_peak,
+ memory_order_relaxed);
+ if (peak_queue < cur_queue)
+ atomic_store_explicit(
+ &fnc->counters.ctxqueue_len_peak,
+ peak_queue, memory_order_relaxed);
+ continue;
+ }
+
+ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
+ dplane_provider_enqueue_out_ctx(prov, ctx);
+ }
+
+ if (atomic_load_explicit(&fnc->counters.ctxqueue_len,
+ memory_order_relaxed)
+ > 0)
+ thread_add_timer(fnc->fthread->master, fpm_process_queue,
+ fnc, 0, &fnc->t_dequeue);
+
+ return 0;
+}
+
+static int fpm_nl_new(struct thread_master *tm)
+{
+ struct zebra_dplane_provider *prov = NULL;
+ int rv;
+
+ gfnc = calloc(1, sizeof(*gfnc));
+ rv = dplane_provider_register(prov_name, DPLANE_PRIO_POSTPROCESS,
+ DPLANE_PROV_FLAG_THREADED, fpm_nl_start,
+ fpm_nl_process, fpm_nl_finish, gfnc,
+ &prov);
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("%s register status: %d", prov_name, rv);
+
+ install_node(&fpm_node);
+ install_element(ENABLE_NODE, &fpm_show_counters_cmd);
+ install_element(ENABLE_NODE, &fpm_show_counters_json_cmd);
+ install_element(ENABLE_NODE, &fpm_reset_counters_cmd);
+ install_element(CONFIG_NODE, &fpm_set_address_cmd);
+ install_element(CONFIG_NODE, &no_fpm_set_address_cmd);
+
+ return 0;
+}
+
+static int fpm_nl_init(void)
+{
+ hook_register(frr_late_init, fpm_nl_new);
+ return 0;
+}
+
+FRR_MODULE_SETUP(
+ .name = "dplane_fpm_nl",
+ .version = "0.0.1",
+ .description = "Data plane plugin for FPM using netlink.",
+ .init = fpm_nl_init,
+ )
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 65a0add57e..78155b1455 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -764,7 +764,7 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family,
if (filter_mask)
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask);
- return netlink_request(netlink_cmd, &req.n);
+ return netlink_request(netlink_cmd, &req);
}
/* Interface lookup by netlink socket. */
diff --git a/zebra/interface.c b/zebra/interface.c
index 59cbfc6854..9a248ba5d1 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -153,7 +153,7 @@ static int if_zebra_new_hook(struct interface *ifp)
rtadv->AdvLinkMTU = 0;
rtadv->AdvReachableTime = 0;
rtadv->AdvRetransTimer = 0;
- rtadv->AdvCurHopLimit = 0;
+ rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
rtadv->AdvDefaultLifetime =
-1; /* derive from MaxRtrAdvInterval */
rtadv->HomeAgentPreference = 0;
@@ -500,7 +500,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags)
/* Wake up configured address if it is not in current kernel
address. */
-static void if_addr_wakeup(struct interface *ifp)
+void if_addr_wakeup(struct interface *ifp)
{
struct listnode *node, *nnode;
struct connected *ifc;
@@ -1664,7 +1664,14 @@ static void interface_update_stats(void)
#endif /* HAVE_NET_RT_IFLIST */
}
-struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1};
+static int if_config_write(struct vty *vty);
+struct cmd_node interface_node = {
+ .name = "interface",
+ .node = INTERFACE_NODE,
+ .parent_node = CONFIG_NODE,
+ .prompt = "%s(config-if)# ",
+ .config_write = if_config_write,
+};
#ifndef VTYSH_EXTRACT_PL
#include "zebra/interface_clippy.c"
@@ -1881,6 +1888,24 @@ DEFUN (show_interface_desc_vrf_all,
return CMD_SUCCESS;
}
+int if_multicast_set(struct interface *ifp)
+{
+ struct zebra_if *if_data;
+
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+ if (if_set_flags(ifp, IFF_MULTICAST) < 0) {
+ zlog_debug("Can't set multicast flag on interface %s",
+ ifp->name);
+ return -1;
+ }
+ if_refresh(ifp);
+ }
+ if_data = ifp->info;
+ if_data->multicast = IF_ZEBRA_MULTICAST_ON;
+
+ return 0;
+}
+
DEFUN (multicast,
multicast_cmd,
"multicast",
@@ -1904,6 +1929,24 @@ DEFUN (multicast,
return CMD_SUCCESS;
}
+int if_multicast_unset(struct interface *ifp)
+{
+ struct zebra_if *if_data;
+
+ if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+ if (if_unset_flags(ifp, IFF_MULTICAST) < 0) {
+ zlog_debug("Can't unset multicast flag on interface %s",
+ ifp->name);
+ return -1;
+ }
+ if_refresh(ifp);
+ }
+ if_data = ifp->info;
+ if_data->multicast = IF_ZEBRA_MULTICAST_OFF;
+
+ return 0;
+}
+
DEFUN (no_multicast,
no_multicast_cmd,
"no multicast",
@@ -1928,23 +1971,35 @@ DEFUN (no_multicast,
return CMD_SUCCESS;
}
-DEFUN (linkdetect,
- linkdetect_cmd,
- "link-detect",
- "Enable link detection on interface\n")
+int if_linkdetect(struct interface *ifp, bool detect)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
int if_was_operative;
if_was_operative = if_is_no_ptm_operative(ifp);
- SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ if (detect) {
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
- /* When linkdetection is enabled, if might come down */
- if (!if_is_no_ptm_operative(ifp) && if_was_operative)
- if_down(ifp);
+ /* When linkdetection is enabled, if might come down */
+ if (!if_is_no_ptm_operative(ifp) && if_was_operative)
+ if_down(ifp);
+ } else {
+ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ /* Interface may come up after disabling link detection */
+ if (if_is_operative(ifp) && !if_was_operative)
+ if_up(ifp);
+ }
/* FIXME: Will defer status change forwarding if interface
does not come down! */
+ return 0;
+}
+
+DEFUN(linkdetect, linkdetect_cmd, "link-detect",
+ "Enable link detection on interface\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+
+ if_linkdetect(ifp, true);
return CMD_SUCCESS;
}
@@ -1957,18 +2012,29 @@ DEFUN (no_linkdetect,
"Disable link detection on interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- int if_was_operative;
- if_was_operative = if_is_no_ptm_operative(ifp);
- UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ if_linkdetect(ifp, false);
+
+ return CMD_SUCCESS;
+}
- /* Interface may come up after disabling link detection */
- if (if_is_operative(ifp) && !if_was_operative)
- if_up(ifp);
+int if_shutdown(struct interface *ifp)
+{
+ struct zebra_if *if_data;
- /* FIXME: see linkdetect_cmd */
+ if (ifp->ifindex != IFINDEX_INTERNAL) {
+ /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+ rtadv_stop_ra(ifp);
+ if (if_unset_flags(ifp, IFF_UP) < 0) {
+ zlog_debug("Can't shutdown interface %s", ifp->name);
+ return -1;
+ }
+ if_refresh(ifp);
+ }
+ if_data = ifp->info;
+ if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
- return CMD_SUCCESS;
+ return 0;
}
DEFUN (shutdown_if,
@@ -1996,6 +2062,30 @@ DEFUN (shutdown_if,
return CMD_SUCCESS;
}
+int if_no_shutdown(struct interface *ifp)
+{
+ struct zebra_if *if_data;
+
+ if (ifp->ifindex != IFINDEX_INTERNAL) {
+ if (if_set_flags(ifp, IFF_UP | IFF_RUNNING) < 0) {
+ zlog_debug("Can't up interface %s", ifp->name);
+ return -1;
+ }
+ if_refresh(ifp);
+
+ /* Some addresses (in particular, IPv6 addresses on Linux) get
+ * removed when the interface goes down. They need to be
+ * readded.
+ */
+ if_addr_wakeup(ifp);
+ }
+
+ if_data = ifp->info;
+ if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+
+ return 0;
+}
+
DEFUN (no_shutdown_if,
no_shutdown_if_cmd,
"no shutdown",
@@ -2074,7 +2164,10 @@ DEFUN (no_bandwidth_if,
struct cmd_node link_params_node = {
- LINK_PARAMS_NODE, "%s(config-link-params)# ", 1,
+ .name = "link-params",
+ .node = LINK_PARAMS_NODE,
+ .parent_node = INTERFACE_NODE,
+ .prompt = "%s(config-link-params)# ",
};
static void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field,
@@ -2748,6 +2841,79 @@ DEFUN (no_link_params_use_bw,
return CMD_SUCCESS;
}
+int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
+ const char *label, struct prefix *pp)
+{
+ struct zebra_if *if_data;
+ struct prefix_ipv4 lp;
+ struct prefix_ipv4 *p;
+ struct connected *ifc;
+ enum zebra_dplane_result dplane_res;
+
+ if_data = ifp->info;
+
+ lp.family = prefix->family;
+ lp.prefix = prefix->u.prefix4;
+ lp.prefixlen = prefix->prefixlen;
+ apply_mask_ipv4(&lp);
+
+ ifc = connected_check_ptp(ifp, &lp, pp ? pp : NULL);
+ if (!ifc) {
+ ifc = connected_new();
+ ifc->ifp = ifp;
+
+ /* Address. */
+ p = prefix_ipv4_new();
+ *p = lp;
+ ifc->address = (struct prefix *)p;
+
+ if (pp) {
+ SET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
+ p = prefix_ipv4_new();
+ *p = *(struct prefix_ipv4 *)pp;
+ ifc->destination = (struct prefix *)p;
+ }
+
+ /* Label. */
+ if (label)
+ ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
+
+ /* Add to linked list. */
+ listnode_add(ifp->connected, ifc);
+ }
+
+ /* This address is configured from zebra. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
+ SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+ /* In case of this route need to install kernel. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+ && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
+ && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ /* Some system need to up the interface to set IP address. */
+ if (!if_is_up(ifp)) {
+ if_set_flags(ifp, IFF_UP | IFF_RUNNING);
+ if_refresh(ifp);
+ }
+
+ dplane_res = dplane_intf_addr_set(ifp, ifc);
+ if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+ zlog_debug(
+ "dplane can't set interface IP address: %s.\n",
+ dplane_res2str(dplane_res));
+ return NB_ERR;
+ }
+
+ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+ /* The address will be advertised to zebra clients when the
+ * notification
+ * from the kernel has been received.
+ * It will also be added to the subnet chain list, then. */
+ }
+
+ return 0;
+}
+
static int ip_address_install(struct vty *vty, struct interface *ifp,
const char *addr_str, const char *peer_str,
const char *label)
@@ -2842,6 +3008,51 @@ static int ip_address_install(struct vty *vty, struct interface *ifp,
return CMD_SUCCESS;
}
+int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix)
+{
+ struct connected *ifc = NULL;
+ enum zebra_dplane_result dplane_res;
+
+ if (prefix->family == AF_INET) {
+ /* Check current interface address. */
+ ifc = connected_check_ptp(ifp, prefix, NULL);
+ if (!ifc) {
+ zlog_debug("interface %s Can't find address\n",
+ ifp->name);
+ return -1;
+ }
+
+ } else if (prefix->family == AF_INET6) {
+ /* Check current interface address. */
+ ifc = connected_check(ifp, prefix);
+ }
+
+ if (!ifc) {
+ zlog_debug("interface %s Can't find address\n", ifp->name);
+ return -1;
+ }
+ UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+ /* This is not real address or interface is not active. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+ || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+ listnode_delete(ifp->connected, ifc);
+ connected_free(&ifc);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* This is real route. */
+ dplane_res = dplane_intf_addr_unset(ifp, ifc);
+ if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+ zlog_debug("Can't unset interface IP address: %s.\n",
+ dplane_res2str(dplane_res));
+ return -1;
+ }
+ UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+
+ return 0;
+}
+
static int ip_address_uninstall(struct vty *vty, struct interface *ifp,
const char *addr_str, const char *peer_str,
const char *label)
@@ -2995,6 +3206,71 @@ DEFUN (no_ip_address_label,
}
#endif /* HAVE_NETLINK */
+int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
+ const char *label)
+{
+ struct zebra_if *if_data;
+ struct prefix_ipv6 cp;
+ struct connected *ifc;
+ struct prefix_ipv6 *p;
+ enum zebra_dplane_result dplane_res;
+
+ if_data = ifp->info;
+
+ cp.family = prefix->family;
+ cp.prefixlen = prefix->prefixlen;
+ cp.prefix = prefix->u.prefix6;
+ apply_mask_ipv6(&cp);
+
+ ifc = connected_check(ifp, (struct prefix *)&cp);
+ if (!ifc) {
+ ifc = connected_new();
+ ifc->ifp = ifp;
+
+ /* Address. */
+ p = prefix_ipv6_new();
+ *p = cp;
+ ifc->address = (struct prefix *)p;
+
+ /* Label. */
+ if (label)
+ ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
+
+ /* Add to linked list. */
+ listnode_add(ifp->connected, ifc);
+ }
+
+ /* This address is configured from zebra. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
+ SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+ /* In case of this route need to install kernel. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+ && CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)
+ && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) {
+ /* Some system need to up the interface to set IP address. */
+ if (!if_is_up(ifp)) {
+ if_set_flags(ifp, IFF_UP | IFF_RUNNING);
+ if_refresh(ifp);
+ }
+
+ dplane_res = dplane_intf_addr_set(ifp, ifc);
+ if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
+ zlog_debug(
+ "dplane can't set interface IP address: %s.\n",
+ dplane_res2str(dplane_res));
+ return NB_ERR;
+ }
+
+ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+ /* The address will be advertised to zebra clients when the
+ * notification
+ * from the kernel has been received. */
+ }
+
+ return 0;
+}
+
static int ipv6_address_install(struct vty *vty, struct interface *ifp,
const char *addr_str, const char *peer_str,
const char *label)
@@ -3311,8 +3587,8 @@ void zebra_if_init(void)
hook_register_prio(if_del, 0, if_zebra_delete_hook);
/* Install configuration write function. */
- install_node(&interface_node, if_config_write);
- install_node(&link_params_node, NULL);
+ install_node(&interface_node);
+ install_node(&link_params_node);
if_cmd_init();
/*
* This is *intentionally* setting this to NULL, signaling
diff --git a/zebra/interface.h b/zebra/interface.h
index b7e90a0c31..2dad0c3bb2 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -117,6 +117,7 @@ struct rtadvconf {
Default: The value specified in the "Assigned Numbers" RFC
[ASSIGNED] that was in effect at the time of implementation. */
int AdvCurHopLimit;
+#define RTADV_DEFAULT_HOPLIMIT 64 /* 64 hops */
/* The value to be placed in the Router Lifetime field of Router
Advertisements sent from the interface, in seconds. MUST be
@@ -440,6 +441,17 @@ extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
ns_id_t ns_id);
extern void zebra_if_update_all_links(void);
extern void zebra_if_set_protodown(struct interface *ifp, bool down);
+extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
+ const char *label, struct prefix *pp);
+extern int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
+ const char *label);
+extern int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix);
+extern int if_shutdown(struct interface *ifp);
+extern int if_no_shutdown(struct interface *ifp);
+extern int if_multicast_set(struct interface *ifp);
+extern int if_multicast_unset(struct interface *ifp);
+extern int if_linkdetect(struct interface *ifp, bool detect);
+extern void if_addr_wakeup(struct interface *ifp);
/* Nexthop group connected functions */
extern void if_nhg_dependents_add(struct interface *ifp,
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index 8e1ca122d3..87a1f5fdc7 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -53,6 +53,7 @@
#include "if.h"
#include "sockunion.h"
#include "log.h"
+#include "network.h"
extern int irdp_sock;
@@ -267,7 +268,7 @@ static void irdp_if_start(struct interface *ifp, int multicast,
}
srandom(seed);
- timer = (random() % IRDP_DEFAULT_INTERVAL) + 1;
+ timer = (frr_weak_random() % IRDP_DEFAULT_INTERVAL) + 1;
irdp->AdvPrefList = list_new();
irdp->AdvPrefList->del = (void (*)(void *))Adv_free; /* Destructor */
diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c
index a1e6e8248e..b868d23a94 100644
--- a/zebra/irdp_main.c
+++ b/zebra/irdp_main.c
@@ -66,6 +66,7 @@
#include "if.h"
#include "sockunion.h"
#include "log.h"
+#include "network.h"
/* GLOBAL VARS */
@@ -233,7 +234,7 @@ int irdp_send_thread(struct thread *t_advert)
}
tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
- timer = random() % (tmp + 1);
+ timer = frr_weak_random() % (tmp + 1);
timer = irdp->MinAdvertInterval + timer;
if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
@@ -303,7 +304,7 @@ void process_solicit(struct interface *ifp)
thread_cancel(irdp->t_advertise);
irdp->t_advertise = NULL;
- timer = (random() % MAX_RESPONSE_DELAY) + 1;
+ timer = (frr_weak_random() % MAX_RESPONSE_DELAY) + 1;
irdp->t_advertise = NULL;
thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 97b0238362..a1f7014ce9 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -1061,10 +1061,11 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
/* Issue request message to kernel via netlink socket. GET messages
* are issued through this interface.
*/
-int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
+int netlink_request(struct nlsock *nl, void *req)
{
int ret;
struct sockaddr_nl snl;
+ struct nlmsghdr *n = (struct nlmsghdr *)req;
/* Check netlink socket. */
if (nl->sock < 0) {
@@ -1082,7 +1083,7 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
/* Raise capabilities and send message, then lower capabilities. */
frr_with_privs(&zserv_privs) {
- ret = sendto(nl->sock, (void *)n, n->nlmsg_len, 0,
+ ret = sendto(nl->sock, req, n->nlmsg_len, 0,
(struct sockaddr *)&snl, sizeof(snl));
}
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 076ca5c5c7..6a4077abf6 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -68,7 +68,7 @@ int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
struct nlmsghdr *n,
const struct zebra_dplane_info *dp_info, int startup);
-extern int netlink_request(struct nlsock *nl, struct nlmsghdr *n);
+extern int netlink_request(struct nlsock *nl, void *req);
#endif /* HAVE_NETLINK */
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index caebdc0f08..93736e672a 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by Bingen Eguzkitza,
* Volta Networks Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * This file is part of FRRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -52,48 +52,45 @@ DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
* externally
*/
-DEFINE_HOOK(lm_client_connect,
- (uint8_t proto, uint16_t instance, vrf_id_t vrf_id),
- (proto, instance, vrf_id));
-DEFINE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance),
- (proto, instance));
+DEFINE_HOOK(lm_client_connect, (struct zserv *client, vrf_id_t vrf_id),
+ (client, vrf_id));
+DEFINE_HOOK(lm_client_disconnect, (struct zserv *client), (client));
DEFINE_HOOK(lm_get_chunk,
- (struct label_manager_chunk * *lmc, uint8_t proto,
- uint16_t instance, uint8_t keep, uint32_t size, uint32_t base,
- vrf_id_t vrf_id),
- (lmc, proto, instance, keep, size, base, vrf_id));
+ (struct label_manager_chunk * *lmc, struct zserv *client,
+ uint8_t keep, uint32_t size, uint32_t base, vrf_id_t vrf_id),
+ (lmc, client, keep, size, base, vrf_id));
DEFINE_HOOK(lm_release_chunk,
- (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end),
- (proto, instance, start, end));
+ (struct zserv *client, uint32_t start, uint32_t end),
+ (client, start, end));
DEFINE_HOOK(lm_cbs_inited, (), ());
/* define wrappers to be called in zapi_msg.c (as hooks must be called in
* source file where they were defined)
*/
-void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id)
+void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id)
{
- hook_call(lm_client_connect, proto, instance, vrf_id);
+ hook_call(lm_client_connect, client, vrf_id);
}
-void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto,
- uint16_t instance, uint8_t keep, uint32_t size,
- uint32_t base, vrf_id_t vrf_id)
+void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client,
+ uint8_t keep, uint32_t size, uint32_t base,
+ vrf_id_t vrf_id)
{
- hook_call(lm_get_chunk, lmc, proto, instance, keep, size, base, vrf_id);
+ hook_call(lm_get_chunk, lmc, client, keep, size, base, vrf_id);
}
-void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start,
- uint32_t end)
+void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end)
{
- hook_call(lm_release_chunk, proto, instance, start, end);
+ hook_call(lm_release_chunk, client, start, end);
}
/* forward declarations of the static functions to be used for some hooks */
-static int label_manager_connect(uint8_t proto, uint16_t instance,
- vrf_id_t vrf_id);
-static int label_manager_disconnect(uint8_t proto, uint16_t instance);
+static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id);
+static int label_manager_disconnect(struct zserv *client);
static int label_manager_get_chunk(struct label_manager_chunk **lmc,
- uint8_t proto, uint16_t instance,
- uint8_t keep, uint32_t size, uint32_t base,
+ struct zserv *client, uint8_t keep,
+ uint32_t size, uint32_t base,
vrf_id_t vrf_id);
+static int label_manager_release_label_chunk(struct zserv *client,
+ uint32_t start, uint32_t end);
void delete_label_chunk(void *val)
{
@@ -110,7 +107,7 @@ void delete_label_chunk(void *val)
* @param instance Instance, to identify the owner
* @return Number of chunks released
*/
-int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
+int release_daemon_label_chunks(struct zserv *client)
{
struct listnode *node;
struct label_manager_chunk *lmc;
@@ -118,13 +115,16 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
int ret;
if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s: Releasing chunks for client proto %s, instance %d",
- __func__, zebra_route_string(proto), instance);
+ zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
+ __func__, zebra_route_string(client->proto),
+ client->instance, client->session_id);
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
- if (lmc->proto == proto && lmc->instance == instance
- && lmc->keep == 0) {
+ if (lmc->proto == client->proto &&
+ lmc->instance == client->instance &&
+ lmc->session_id == client->session_id && lmc->keep == 0) {
ret = release_label_chunk(lmc->proto, lmc->instance,
+ lmc->session_id,
lmc->start, lmc->end);
if (ret == 0)
count++;
@@ -139,10 +139,7 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
int lm_client_disconnect_cb(struct zserv *client)
{
- uint8_t proto = client->proto;
- uint16_t instance = client->instance;
-
- hook_call(lm_client_disconnect, proto, instance);
+ hook_call(lm_client_disconnect, client);
return 0;
}
@@ -151,14 +148,14 @@ void lm_hooks_register(void)
hook_register(lm_client_connect, label_manager_connect);
hook_register(lm_client_disconnect, label_manager_disconnect);
hook_register(lm_get_chunk, label_manager_get_chunk);
- hook_register(lm_release_chunk, release_label_chunk);
+ hook_register(lm_release_chunk, label_manager_release_label_chunk);
}
void lm_hooks_unregister(void)
{
hook_unregister(lm_client_connect, label_manager_connect);
hook_unregister(lm_client_disconnect, label_manager_disconnect);
hook_unregister(lm_get_chunk, label_manager_get_chunk);
- hook_unregister(lm_release_chunk, release_label_chunk);
+ hook_unregister(lm_release_chunk, label_manager_release_label_chunk);
}
/**
@@ -180,6 +177,7 @@ void label_manager_init(void)
/* alloc and fill a label chunk */
struct label_manager_chunk *create_label_chunk(uint8_t proto,
unsigned short instance,
+ uint32_t session_id,
uint8_t keep, uint32_t start,
uint32_t end)
{
@@ -191,6 +189,7 @@ struct label_manager_chunk *create_label_chunk(uint8_t proto,
lmc->end = end;
lmc->proto = proto;
lmc->instance = instance;
+ lmc->session_id = session_id;
lmc->keep = keep;
return lmc;
@@ -199,7 +198,8 @@ struct label_manager_chunk *create_label_chunk(uint8_t proto,
/* attempt to get a specific label chunk */
static struct label_manager_chunk *
assign_specific_label_chunk(uint8_t proto, unsigned short instance,
- uint8_t keep, uint32_t size, uint32_t base)
+ uint32_t session_id, uint8_t keep, uint32_t size,
+ uint32_t base)
{
struct label_manager_chunk *lmc;
struct listnode *node, *next = NULL;
@@ -248,7 +248,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
/* insert chunk between existing chunks */
if (insert_node) {
- lmc = create_label_chunk(proto, instance, keep, base, end);
+ lmc = create_label_chunk(proto, instance, session_id, keep,
+ base, end);
listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);
return lmc;
}
@@ -270,7 +271,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
delete_label_chunk(death);
}
- lmc = create_label_chunk(proto, instance, keep, base, end);
+ lmc = create_label_chunk(proto, instance, session_id, keep,
+ base, end);
if (last_node)
listnode_add_before(lbl_mgr.lc_list, last_node, lmc);
else
@@ -280,7 +282,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
} else {
/* create a new chunk past all the existing ones and link at
* tail */
- lmc = create_label_chunk(proto, instance, keep, base, end);
+ lmc = create_label_chunk(proto, instance, session_id, keep,
+ base, end);
listnode_add(lbl_mgr.lc_list, lmc);
return lmc;
}
@@ -301,6 +304,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
*/
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
unsigned short instance,
+ uint32_t session_id,
uint8_t keep, uint32_t size,
uint32_t base)
{
@@ -310,8 +314,8 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
/* handle chunks request with a specific base label */
if (base != MPLS_LABEL_BASE_ANY)
- return assign_specific_label_chunk(proto, instance, keep, size,
- base);
+ return assign_specific_label_chunk(proto, instance, session_id,
+ keep, size, base);
/* appease scan-build, who gets confused by the use of macros */
assert(lbl_mgr.lc_list);
@@ -322,6 +326,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
&& lmc->end - lmc->start + 1 == size) {
lmc->proto = proto;
lmc->instance = instance;
+ lmc->session_id = session_id;
lmc->keep = keep;
return lmc;
}
@@ -329,8 +334,9 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
*/
if ((lmc->start > prev_end)
&& (lmc->start - prev_end >= size)) {
- lmc = create_label_chunk(proto, instance, keep,
- prev_end + 1, prev_end + size);
+ lmc = create_label_chunk(proto, instance, session_id,
+ keep, prev_end + 1,
+ prev_end + size);
listnode_add_before(lbl_mgr.lc_list, node, lmc);
return lmc;
}
@@ -355,13 +361,31 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
}
/* create chunk and link at tail */
- lmc = create_label_chunk(proto, instance, keep, start_free,
+ lmc = create_label_chunk(proto, instance, session_id, keep, start_free,
start_free + size - 1);
listnode_add(lbl_mgr.lc_list, lmc);
return lmc;
}
/**
+ * Release label chunks from a client.
+ *
+ * Called on client disconnection or reconnection. It only releases chunks
+ * with empty keep value.
+ *
+ * @param client Client zapi session
+ * @param start First label of the chunk
+ * @param end Last label of the chunk
+ * @return 0 on success
+ */
+static int label_manager_release_label_chunk(struct zserv *client,
+ uint32_t start, uint32_t end)
+{
+ return release_label_chunk(client->proto, client->instance,
+ client->session_id, start, end);
+}
+
+/**
* Core function, release no longer used label chunks
*
* @param proto Daemon protocol of client, to identify the owner
@@ -370,8 +394,8 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
* @param end Last label of the chunk
* @return 0 on success, -1 otherwise
*/
-int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
- uint32_t end)
+int release_label_chunk(uint8_t proto, unsigned short instance,
+ uint32_t session_id, uint32_t start, uint32_t end)
{
struct listnode *node;
struct label_manager_chunk *lmc;
@@ -386,13 +410,15 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
continue;
if (lmc->end != end)
continue;
- if (lmc->proto != proto || lmc->instance != instance) {
+ if (lmc->proto != proto || lmc->instance != instance ||
+ lmc->session_id != session_id) {
flog_err(EC_ZEBRA_LM_DAEMON_MISMATCH,
"%s: Daemon mismatch!!", __func__);
continue;
}
lmc->proto = NO_PROTO;
lmc->instance = 0;
+ lmc->session_id = 0;
lmc->keep = 0;
ret = 0;
break;
@@ -405,55 +431,60 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
}
/* default functions to be called on hooks */
-static int label_manager_connect(uint8_t proto, uint16_t instance,
- vrf_id_t vrf_id)
+static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id)
{
/*
* Release previous labels of same protocol and instance.
* This is done in case it restarted from an unexpected shutdown.
*/
- release_daemon_label_chunks(proto, instance);
- return lm_client_connect_response(proto, instance, vrf_id, 0);
+ release_daemon_label_chunks(client);
+ return zsend_label_manager_connect_response(client, vrf_id, 0);
}
-static int label_manager_disconnect(uint8_t proto, uint16_t instance)
+static int label_manager_disconnect(struct zserv *client)
{
- release_daemon_label_chunks(proto, instance);
+ release_daemon_label_chunks(client);
return 0;
}
static int label_manager_get_chunk(struct label_manager_chunk **lmc,
- uint8_t proto, uint16_t instance,
- uint8_t keep, uint32_t size, uint32_t base,
+ struct zserv *client, uint8_t keep,
+ uint32_t size, uint32_t base,
vrf_id_t vrf_id)
{
- *lmc = assign_label_chunk(proto, instance, keep, size, base);
- return lm_get_chunk_response(*lmc, proto, instance, vrf_id);
+ *lmc = assign_label_chunk(client->proto, client->instance,
+ client->session_id, keep, size, base);
+ return lm_get_chunk_response(*lmc, client, vrf_id);
}
/* Respond to a connect request */
int lm_client_connect_response(uint8_t proto, uint16_t instance,
- vrf_id_t vrf_id, uint8_t result)
+ uint32_t session_id, vrf_id_t vrf_id,
+ uint8_t result)
{
- struct zserv *client = zserv_find_client(proto, instance);
+ struct zserv *client = zserv_find_client_session(proto, instance,
+ session_id);
if (!client) {
- zlog_err("%s: could not find client for daemon %s instance %u",
- __func__, zebra_route_string(proto), instance);
+ zlog_err("%s: could not find client for daemon %s instance %u session %u",
+ __func__, zebra_route_string(proto), instance,
+ session_id);
return 1;
}
return zsend_label_manager_connect_response(client, vrf_id, result);
}
/* Respond to a get_chunk request */
-int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto,
- uint16_t instance, vrf_id_t vrf_id)
+int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client,
+ vrf_id_t vrf_id)
{
- struct zserv *client = zserv_find_client(proto, instance);
- if (!client) {
- zlog_err("%s: could not find client for daemon %s instance %u",
- __func__, zebra_route_string(proto), instance);
- return 1;
- }
- return zsend_assign_label_chunk_response(client, vrf_id, proto,
- instance, lmc);
+ if (!lmc)
+ flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
+ "Unable to assign Label Chunk to %s instance %u",
+ zebra_route_string(client->proto), client->instance);
+ else if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
+ lmc->start, lmc->end,
+ zebra_route_string(client->proto), client->instance);
+
+ return zsend_assign_label_chunk_response(client, vrf_id, lmc);
}
void label_manager_close(void)
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
index 74e283e85e..82154982c2 100644
--- a/zebra/label_manager.h
+++ b/zebra/label_manager.h
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by Bingen Eguzkitza,
* Volta Networks Inc.
*
- * This file is part of FreeRangeRouting (FRR)
+ * This file is part of FRRouting (FRR)
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -40,19 +40,20 @@ extern "C" {
/*
* Label chunk struct
- * Client daemon which the chunk belongs to can be identified by either
- * proto (daemon protocol) + instance.
+ * Client daemon which the chunk belongs to can be identified by a tuple of:
+ * proto (daemon protocol) + instance + zapi session_id
* If the client then passes a non-empty value to keep field when it requests
* for chunks, the chunks won't be garbage collected and the client will be
- * responsible of its release.
+ * responsible for releasing them.
* Otherwise, if the keep field is not set (value 0) for the chunk, it will be
* automatically released when the client disconnects or when it reconnects
* (in case it died unexpectedly, we can know it's the same because it will have
- * the same proto and instance values)
+ * the same proto+instance+session values)
*/
struct label_manager_chunk {
uint8_t proto;
unsigned short instance;
+ uint32_t session_id;
uint8_t keep;
uint32_t start; /* First label of the chunk */
uint32_t end; /* Last label of the chunk */
@@ -63,41 +64,40 @@ struct label_manager_chunk {
* so that any external module wanting to replace those can react
*/
-DECLARE_HOOK(lm_client_connect,
- (uint8_t proto, uint16_t instance, vrf_id_t vrf_id),
- (proto, instance, vrf_id));
-DECLARE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance),
- (proto, instance));
+DECLARE_HOOK(lm_client_connect, (struct zserv *client, vrf_id_t vrf_id),
+ (client, vrf_id));
+DECLARE_HOOK(lm_client_disconnect, (struct zserv *client), (client));
DECLARE_HOOK(lm_get_chunk,
- (struct label_manager_chunk * *lmc, uint8_t proto,
- uint16_t instance, uint8_t keep, uint32_t size, uint32_t base,
- vrf_id_t vrf_id),
- (lmc, proto, instance, keep, size, base, vrf_id));
+ (struct label_manager_chunk * *lmc, struct zserv *client,
+ uint8_t keep, uint32_t size, uint32_t base, vrf_id_t vrf_id),
+ (lmc, client, keep, size, base, vrf_id));
DECLARE_HOOK(lm_release_chunk,
- (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end),
- (proto, instance, start, end));
+ (struct zserv *client, uint32_t start, uint32_t end),
+ (client, start, end));
DECLARE_HOOK(lm_cbs_inited, (), ());
/* declare wrappers to be called in zapi_msg.c (as hooks must be called in
* source file where they were defined)
*/
-void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id);
-void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto,
- uint16_t instance, uint8_t keep, uint32_t size,
- uint32_t base, vrf_id_t vrf_id);
-void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start,
+void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id);
+void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client,
+ uint8_t keep, uint32_t size, uint32_t base,
+ vrf_id_t vrf_id);
+void lm_release_chunk_call(struct zserv *client, uint32_t start,
uint32_t end);
/* API for an external LM to return responses for requests */
int lm_client_connect_response(uint8_t proto, uint16_t instance,
- vrf_id_t vrf_id, uint8_t result);
-int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto,
- uint16_t instance, vrf_id_t vrf_id);
+ uint32_t session_id, vrf_id_t vrf_id,
+ uint8_t result);
+int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client,
+ vrf_id_t vrf_id);
/* convenience function to allocate an lmc to be consumed by the above API */
struct label_manager_chunk *create_label_chunk(uint8_t proto,
unsigned short instance,
+ uint32_t session_id,
uint8_t keep, uint32_t start,
uint32_t end);
void delete_label_chunk(void *val);
@@ -117,12 +117,13 @@ struct label_manager {
void label_manager_init(void);
struct label_manager_chunk *assign_label_chunk(uint8_t proto,
unsigned short instance,
+ uint32_t session_id,
uint8_t keep, uint32_t size,
uint32_t base);
-int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
- uint32_t end);
+int release_label_chunk(uint8_t proto, unsigned short instance,
+ uint32_t session_id, uint32_t start, uint32_t end);
int lm_client_disconnect_cb(struct zserv *client);
-int release_daemon_label_chunks(uint8_t proto, unsigned short instance);
+int release_daemon_label_chunks(struct zserv *client);
void label_manager_close(void);
#ifdef __cplusplus
diff --git a/zebra/main.c b/zebra/main.c
index dab1449194..e230a744f6 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -54,6 +54,7 @@
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_routemap.h"
+#include "zebra/zebra_nb.h"
#if defined(HANDLE_NETLINK_FUZZING)
#include "zebra/kernel_netlink.h"
@@ -174,6 +175,7 @@ static void sigint(void)
work_queue_free_and_null(&zrouter.lsp_process_q);
vrf_terminate();
+ rtadv_terminate();
ns_walk_func(zebra_ns_early_shutdown);
zebra_ns_notify_close();
@@ -245,6 +247,8 @@ struct quagga_signal_t zebra_signals[] = {
static const struct frr_yang_module_info *const zebra_yang_modules[] = {
&frr_interface_info,
&frr_route_map_info,
+ &frr_zebra_info,
+ &frr_vrf_info,
};
FRR_DAEMON_INFO(
@@ -329,17 +333,21 @@ int main(int argc, char **argv)
case 'a':
allow_delete = 1;
break;
- case 'e':
- zrouter.multipath_num = atoi(optarg);
- if (zrouter.multipath_num > MULTIPATH_NUM
- || zrouter.multipath_num <= 0) {
+ case 'e': {
+ unsigned long int parsed_multipath =
+ strtoul(optarg, NULL, 10);
+ if (parsed_multipath == 0
+ || parsed_multipath > MULTIPATH_NUM
+ || parsed_multipath > UINT32_MAX) {
flog_err(
EC_ZEBRA_BAD_MULTIPATH_NUM,
- "Multipath Number specified must be less than %d and greater than 0",
+ "Multipath Number specified must be less than %u and greater than 0",
MULTIPATH_NUM);
return 1;
}
+ zrouter.multipath_num = parsed_multipath;
break;
+ }
case 'o':
vrf_default_name_configured = optarg;
break;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 115a69f2c8..4d6346151a 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -150,6 +150,43 @@ static void zebra_redistribute(struct zserv *client, int type,
}
}
+/*
+ * Function to check if prefix is candidate for
+ * redistribute.
+ */
+static bool zebra_redistribute_check(const struct route_entry *re,
+ struct zserv *client,
+ const struct prefix *p, int afi)
+{
+ /* Process only if there is valid re */
+ if (!re)
+ return false;
+
+ /* If default route and redistributed */
+ if (is_default_prefix(p)
+ && vrf_bitmap_check(client->redist_default[afi], re->vrf_id))
+ return true;
+
+ /* If redistribute in enabled for zebra route all */
+ if (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], re->vrf_id))
+ return true;
+
+ /*
+ * If multi-instance then check for route
+ * redistribution for given instance.
+ */
+ if (re->instance
+ && redist_check_instance(&client->mi_redist[afi][re->type],
+ re->instance))
+ return true;
+
+ /* If redistribution is enabled for give route type. */
+ if (vrf_bitmap_check(client->redist[afi][re->type], re->vrf_id))
+ return true;
+
+ return false;
+}
+
/* Either advertise a route for redistribution to registered clients or */
/* withdraw redistribution if add cannot be done for client */
void redistribute_update(const struct prefix *p, const struct prefix *src_p,
@@ -158,7 +195,6 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
{
struct listnode *node, *nnode;
struct zserv *client;
- int send_redistribute;
int afi;
char buf[PREFIX_STRLEN];
@@ -185,25 +221,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
- send_redistribute = 0;
-
- if (is_default_prefix(p)
- && vrf_bitmap_check(client->redist_default[afi],
- re->vrf_id))
- send_redistribute = 1;
- else if (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL],
- re->vrf_id))
- send_redistribute = 1;
- else if (re->instance
- && redist_check_instance(
- &client->mi_redist[afi][re->type],
- re->instance))
- send_redistribute = 1;
- else if (vrf_bitmap_check(client->redist[afi][re->type],
- re->vrf_id))
- send_redistribute = 1;
-
- if (send_redistribute) {
+ if (zebra_redistribute_check(re, client, p, afi)) {
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
"%s: client %s %s(%u), type=%d, distance=%d, metric=%d",
@@ -215,18 +233,9 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
}
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
client, p, src_p, re);
- } else if (prev_re
- && ((re->instance
- && redist_check_instance(
- &client->mi_redist[afi]
- [prev_re->type],
- re->instance))
- || vrf_bitmap_check(
- client->redist[afi][prev_re->type],
- re->vrf_id))) {
+ } else if (zebra_redistribute_check(prev_re, client, p, afi))
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
client, p, src_p, prev_re);
- }
}
}
@@ -294,46 +303,21 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
/* Do not send unsolicited messages to synchronous clients. */
if (client->synchronous)
continue;
-
- if (new_re) {
- /* Skip this client if it will receive an update for the
- * 'new' re
- */
- if (is_default_prefix(p)
- && vrf_bitmap_check(client->redist_default[afi],
- new_re->vrf_id))
- continue;
- else if (vrf_bitmap_check(
- client->redist[afi][ZEBRA_ROUTE_ALL],
- new_re->vrf_id))
- continue;
- else if (new_re->instance
- && redist_check_instance(
- &client->mi_redist[afi][new_re->type],
- new_re->instance))
- continue;
- else if (vrf_bitmap_check(
- client->redist[afi][new_re->type],
- new_re->vrf_id))
- continue;
- }
+ /*
+ * Skip this client if it will receive an update for the
+ * 'new' re
+ */
+ if (zebra_redistribute_check(new_re, client, p, afi))
+ continue;
/* Send a delete for the 'old' re to any subscribed client. */
- if (old_re
- && (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL],
- old_re->vrf_id)
- || (old_re->instance
- && redist_check_instance(
- &client->mi_redist[afi][old_re->type],
- old_re->instance))
- || vrf_bitmap_check(client->redist[afi][old_re->type],
- old_re->vrf_id))) {
+ if (zebra_redistribute_check(old_re, client, p, afi))
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
client, p, src_p, old_re);
- }
}
}
+
void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
{
afi_t afi = 0;
diff --git a/zebra/rib.h b/zebra/rib.h
index 931c97638e..3717a12814 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -107,7 +107,7 @@ struct route_entry {
/* Uptime. */
time_t uptime;
- /* Type fo this route. */
+ /* Type of this route. */
int type;
/* VRF identifier. */
@@ -347,10 +347,16 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
uint32_t mtu, uint8_t distance, route_tag_t tag);
-
+/*
+ * Multipath route apis.
+ */
extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct prefix_ipv6 *src_p, struct route_entry *re,
struct nexthop_group *ng);
+extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p,
+ struct route_entry *re,
+ struct nhg_hash_entry *nhe);
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 5a1ae2c217..5c9d2f69a6 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -718,14 +718,15 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (IS_ZEBRA_DEBUG_KERNEL) {
char buf[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
- zlog_debug("%s %s%s%s vrf %u(%u) metric: %d Admin Distance: %d",
- nl_msg_type_to_str(h->nlmsg_type),
- prefix2str(&p, buf, sizeof(buf)),
- src_p.prefixlen ? " from " : "",
- src_p.prefixlen
- ? prefix2str(&src_p, buf2, sizeof(buf2))
- : "",
- vrf_id, table, metric, distance);
+ zlog_debug(
+ "%s %s%s%s vrf %s(%u) table_id: %u metric: %d Admin Distance: %d",
+ nl_msg_type_to_str(h->nlmsg_type),
+ prefix2str(&p, buf, sizeof(buf)),
+ src_p.prefixlen ? " from " : "",
+ src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
+ : "",
+ vrf_id_to_name(vrf_id), vrf_id, table, metric,
+ distance);
}
afi_t afi = AFI_IP;
@@ -911,9 +912,8 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h,
ifp = if_lookup_by_index(iif, vrf);
zlog_debug(
"MCAST VRF: %s(%d) %s (%s,%s) IIF: %s(%d) OIF: %s jiffies: %lld",
- (zvrf ? zvrf->vrf->name : "Unknown"), vrf,
- nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf,
- ifp ? ifp->name : "Unknown", iif, oif_list,
+ zvrf_name(zvrf), vrf, nl_msg_type_to_str(h->nlmsg_type),
+ sbuf, gbuf, ifp ? ifp->name : "Unknown", iif, oif_list,
m->lastused);
}
return 0;
@@ -983,7 +983,7 @@ static int netlink_request_route(struct zebra_ns *zns, int family, int type)
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.rtm.rtm_family = family;
- return netlink_request(&zns->netlink_cmd, &req.n);
+ return netlink_request(&zns->netlink_cmd, &req);
}
/* Routing table read function using netlink interface. Only called
@@ -1122,9 +1122,13 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
+ struct vrf *vrf;
+ char addrstr[INET6_ADDRSTRLEN];
assert(nexthop);
+ vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
/*
* label_buf is *only* currently used within debugging.
* As such when we assign it we are guarding it inside
@@ -1176,10 +1180,10 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
&nexthop->src.ipv4, bytelen);
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- " 5549: _netlink_route_build_singlepath() (%s): %pFX nexthop via %s %s if %u(%u)",
- routedesc, p, ipv4_ll_buf, label_buf,
- nexthop->ifindex, nexthop->vrf_id);
+ zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
+ __func__, routedesc, p, ipv4_ll_buf,
+ label_buf, nexthop->ifindex,
+ VRF_LOGNAME(vrf), nexthop->vrf_id);
return;
}
@@ -1200,11 +1204,14 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
&nexthop->src.ipv4, bytelen);
}
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)",
- routedesc, p, inet_ntoa(nexthop->gate.ipv4),
- label_buf, nexthop->ifindex, nexthop->vrf_id);
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ inet_ntop(AF_INET, &nexthop->gate.ipv4, addrstr,
+ sizeof(addrstr));
+ zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
+ __func__, routedesc, p, addrstr, label_buf,
+ nexthop->ifindex, VRF_LOGNAME(vrf),
+ nexthop->vrf_id);
+ }
}
if (nexthop->type == NEXTHOP_TYPE_IPV6
@@ -1222,11 +1229,14 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
&nexthop->src.ipv6, bytelen);
}
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)",
- routedesc, p, inet6_ntoa(nexthop->gate.ipv6),
- label_buf, nexthop->ifindex, nexthop->vrf_id);
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6, addrstr,
+ sizeof(addrstr));
+ zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
+ __func__, routedesc, p, addrstr, label_buf,
+ nexthop->ifindex, VRF_LOGNAME(vrf),
+ nexthop->vrf_id);
+ }
}
/*
@@ -1248,10 +1258,9 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
}
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via if %u(%u)",
- routedesc, p, nexthop->ifindex,
- nexthop->vrf_id);
+ zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
+ __func__, routedesc, p, nexthop->ifindex,
+ VRF_LOGNAME(vrf), nexthop->vrf_id);
}
}
@@ -1280,6 +1289,7 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
+ struct vrf *vrf;
rtnh->rtnh_len = sizeof(*rtnh);
rtnh->rtnh_flags = 0;
@@ -1288,6 +1298,8 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
assert(nexthop);
+ vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
/*
* label_buf is *only* currently used within debugging.
* As such when we assign it we are guarding it inside
@@ -1347,9 +1359,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- " 5549: netlink_route_build_multipath() (%s): %pFX nexthop via %s %s if %u",
- routedesc, p, ipv4_ll_buf, label_buf,
- nexthop->ifindex);
+ "%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
+ __func__, routedesc, p, ipv4_ll_buf, label_buf,
+ nexthop->ifindex, VRF_LOGNAME(vrf),
+ nexthop->vrf_id);
return;
}
@@ -1364,10 +1377,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u",
- routedesc, p, inet_ntoa(nexthop->gate.ipv4),
- label_buf, nexthop->ifindex);
+ zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %s(%u)",
+ __func__, routedesc, p, &nexthop->gate.ipv4,
+ label_buf, nexthop->ifindex,
+ VRF_LOGNAME(vrf), nexthop->vrf_id);
}
if (nexthop->type == NEXTHOP_TYPE_IPV6
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
@@ -1381,10 +1394,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u",
- routedesc, p, inet6_ntoa(nexthop->gate.ipv6),
- label_buf, nexthop->ifindex);
+ zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %s(%u)",
+ __func__, routedesc, p, &nexthop->gate.ipv6,
+ label_buf, nexthop->ifindex,
+ VRF_LOGNAME(vrf), nexthop->vrf_id);
}
/*
@@ -1403,9 +1416,9 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): %pFX nexthop via if %u",
- routedesc, p, nexthop->ifindex);
+ zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
+ __func__, routedesc, p, nexthop->ifindex,
+ VRF_LOGNAME(vrf), nexthop->vrf_id);
}
if (nexthop->weight)
@@ -1444,37 +1457,6 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
rta, rtnh, rtmsg, src);
}
-
-/* Log debug information for netlink_route_multipath
- * if debug logging is enabled.
- *
- * @param cmd: Netlink command which is to be processed
- * @param p: Prefix for which the change is due
- * @param family: Address family which the change concerns
- * @param zvrf: The vrf we are in
- * @param tableid: The table we are working on
- */
-static void _netlink_route_debug(int cmd, const struct prefix *p,
- int family, vrf_id_t vrfid,
- uint32_t tableid)
-{
- if (IS_ZEBRA_DEBUG_KERNEL) {
- char buf[PREFIX_STRLEN];
- zlog_debug(
- "netlink_route_multipath(): %s %s vrf %u(%u)",
- nl_msg_type_to_str(cmd),
- prefix2str(p, buf, sizeof(buf)),
- vrfid, tableid);
- }
-}
-
-static void _netlink_nexthop_debug(int cmd, uint32_t id)
-{
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("netlink_nexthop(): %s, id=%u",
- nl_msg_type_to_str(cmd), id);
-}
-
static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1539,15 +1521,32 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family,
return false;
}
+static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
+ struct nexthop *nh)
+{
+ struct rtattr *nest;
+
+ switch (nh->nh_encap_type) {
+ case NET_VXLAN:
+ addattr_l(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type,
+ sizeof(uint16_t));
+
+ nest = addattr_nest(n, nlen, RTA_ENCAP);
+ addattr32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni);
+ addattr_nest_end(n, nest);
+ break;
+ }
+}
+
/*
* Routing table change via netlink interface, using a dataplane context object
*/
-static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
+ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
+ uint8_t *data, size_t datalen, bool fpm)
{
int bytelen;
struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
- int family;
const char *routedesc;
bool setsrc = false;
union g_addr src;
@@ -1557,38 +1556,36 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
struct {
struct nlmsghdr n;
struct rtmsg r;
- char buf[NL_PKT_BUF_SIZE];
- } req;
+ char buf[];
+ } *req = (void *)data;
p = dplane_ctx_get_dest(ctx);
src_p = dplane_ctx_get_src(ctx);
- family = PREFIX_FAMILY(p);
+ memset(req, 0, sizeof(*req));
- memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
-
- bytelen = (family == AF_INET ? 4 : 16);
+ bytelen = (p->family == AF_INET ? 4 : 16);
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
if ((cmd == RTM_NEWROUTE) &&
((p->family == AF_INET) || v6_rr_semantics))
- req.n.nlmsg_flags |= NLM_F_REPLACE;
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
- req.n.nlmsg_type = cmd;
+ req->n.nlmsg_type = cmd;
- req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+ req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
- req.r.rtm_family = family;
- req.r.rtm_dst_len = p->prefixlen;
- req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req->r.rtm_family = p->family;
+ req->r.rtm_dst_len = p->prefixlen;
+ req->r.rtm_src_len = src_p ? src_p->prefixlen : 0;
+ req->r.rtm_scope = RT_SCOPE_UNIVERSE;
if (cmd == RTM_DELROUTE)
- req.r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx));
+ req->r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx));
else
- req.r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx));
+ req->r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx));
/*
* blackhole routes are not RTN_UNICAST, they are
@@ -1599,12 +1596,11 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
* the RTM_DELROUTE case
*/
if (cmd != RTM_DELROUTE)
- req.r.rtm_type = RTN_UNICAST;
+ req->r.rtm_type = RTN_UNICAST;
- addattr_l(&req.n, sizeof(req), RTA_DST, &p->u.prefix, bytelen);
+ addattr_l(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen);
if (src_p)
- addattr_l(&req.n, sizeof(req), RTA_SRC, &src_p->u.prefix,
- bytelen);
+ addattr_l(&req->n, datalen, RTA_SRC, &src_p->u.prefix, bytelen);
/* Metric. */
/* Hardcode the metric for all routes coming from zebra. Metric isn't
@@ -1613,7 +1609,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
* path(s)
* by the routing protocol and for communicating with protocol peers.
*/
- addattr32(&req.n, sizeof(req), RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
+ addattr32(&req->n, datalen, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
#if defined(SUPPORT_REALMS)
{
@@ -1625,19 +1621,23 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
tag = dplane_ctx_get_tag(ctx);
if (tag > 0 && tag <= 255)
- addattr32(&req.n, sizeof(req), RTA_FLOW, tag);
+ addattr32(&req->n, datalen, RTA_FLOW, tag);
}
#endif
/* Table corresponding to this route. */
table_id = dplane_ctx_get_table(ctx);
if (table_id < 256)
- req.r.rtm_table = table_id;
+ req->r.rtm_table = table_id;
else {
- req.r.rtm_table = RT_TABLE_UNSPEC;
- addattr32(&req.n, sizeof(req), RTA_TABLE, table_id);
+ req->r.rtm_table = RT_TABLE_UNSPEC;
+ addattr32(&req->n, datalen, RTA_TABLE, table_id);
}
- _netlink_route_debug(cmd, p, family, dplane_ctx_get_vrf(ctx), table_id);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s: %s %pFX vrf %u(%u)", __func__,
+ nl_msg_type_to_str(cmd), p, dplane_ctx_get_vrf(ctx),
+ table_id);
/*
* If we are not updating the route and we have received
@@ -1646,7 +1646,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
* it.
*/
if (cmd == RTM_DELROUTE)
- goto skip;
+ return req->n.nlmsg_len;
if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) {
char buf[NL_PKT_BUF_SIZE];
@@ -1660,7 +1660,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
rta->rta_len = RTA_LENGTH(0);
rta_addattr_l(rta, NL_PKT_BUF_SIZE,
RTAX_MTU, &mtu, sizeof(mtu));
- addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA(rta),
+ addattr_l(&req->n, datalen, RTA_METRICS, RTA_DATA(rta),
RTA_PAYLOAD(rta));
}
@@ -1670,7 +1670,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
zlog_debug(
"netlink_route_multipath(): %pFX nhg_id is %u",
p, dplane_ctx_get_nhe_id(ctx));
- addattr32(&req.n, sizeof(req), RTA_NH_ID,
+
+ addattr32(&req->n, datalen, RTA_NH_ID,
dplane_ctx_get_nhe_id(ctx));
/* Have to determine src still */
@@ -1678,18 +1679,19 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (setsrc)
break;
- setsrc = nexthop_set_src(nexthop, family, &src);
+ setsrc = nexthop_set_src(nexthop, p->family, &src);
}
if (setsrc) {
- if (family == AF_INET)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ if (p->family == AF_INET)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv4, bytelen);
- else if (family == AF_INET6)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ else if (p->family == AF_INET6)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv6, bytelen);
}
- goto skip;
+
+ return req->n.nlmsg_len;
}
/* Count overall nexthops so we can decide whether to use singlepath
@@ -1699,7 +1701,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
- if (cmd == RTM_NEWROUTE && !NEXTHOP_IS_ACTIVE(nexthop->flags))
+ if (!NEXTHOP_IS_ACTIVE(nexthop->flags))
continue;
nexthop_num++;
@@ -1719,16 +1721,16 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
switch (nexthop->bh_type) {
case BLACKHOLE_ADMINPROHIB:
- req.r.rtm_type = RTN_PROHIBIT;
+ req->r.rtm_type = RTN_PROHIBIT;
break;
case BLACKHOLE_REJECT:
- req.r.rtm_type = RTN_UNREACHABLE;
+ req->r.rtm_type = RTN_UNREACHABLE;
break;
default:
- req.r.rtm_type = RTN_BLACKHOLE;
+ req->r.rtm_type = RTN_BLACKHOLE;
break;
}
- goto skip;
+ return req->n.nlmsg_len;
}
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE)) {
@@ -1736,30 +1738,38 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (setsrc)
continue;
- setsrc = nexthop_set_src(nexthop, family, &src);
-
+ setsrc = nexthop_set_src(nexthop, p->family,
+ &src);
continue;
}
- if ((cmd == RTM_NEWROUTE
- && NEXTHOP_IS_ACTIVE(nexthop->flags))) {
+ if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
routedesc = nexthop->rparent
? "recursive, single-path"
: "single-path";
_netlink_route_build_singlepath(
- p, routedesc, bytelen, nexthop, &req.n,
- &req.r, sizeof(req), cmd);
+ p, routedesc, bytelen, nexthop, &req->n,
+ &req->r, datalen, cmd);
nexthop_num++;
break;
}
+
+ /*
+ * Add encapsulation information when installing via
+ * FPM.
+ */
+ if (fpm)
+ netlink_route_nexthop_encap(&req->n, datalen,
+ nexthop);
}
+
if (setsrc) {
- if (family == AF_INET)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ if (p->family == AF_INET)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv4, bytelen);
- else if (family == AF_INET6)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ else if (p->family == AF_INET6)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv6, bytelen);
}
} else { /* Multipath case */
@@ -1780,13 +1790,12 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
if (setsrc)
continue;
- setsrc = nexthop_set_src(nexthop, family, &src);
-
+ setsrc = nexthop_set_src(nexthop, p->family,
+ &src);
continue;
}
- if ((cmd == RTM_NEWROUTE
- && NEXTHOP_IS_ACTIVE(nexthop->flags))) {
+ if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
routedesc = nexthop->rparent
? "recursive, multipath"
: "multipath";
@@ -1794,47 +1803,51 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
_netlink_route_build_multipath(
p, routedesc, bytelen, nexthop, rta,
- rtnh, &req.r, &src1);
+ rtnh, &req->r, &src1);
rtnh = RTNH_NEXT(rtnh);
if (!setsrc && src1) {
- if (family == AF_INET)
+ if (p->family == AF_INET)
src.ipv4 = src1->ipv4;
- else if (family == AF_INET6)
+ else if (p->family == AF_INET6)
src.ipv6 = src1->ipv6;
setsrc = 1;
}
}
+
+ /*
+ * Add encapsulation information when installing via
+ * FPM.
+ */
+ if (fpm)
+ netlink_route_nexthop_encap(&req->n, datalen,
+ nexthop);
}
+
if (setsrc) {
- if (family == AF_INET)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ if (p->family == AF_INET)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv4, bytelen);
- else if (family == AF_INET6)
- addattr_l(&req.n, sizeof(req), RTA_PREFSRC,
+ else if (p->family == AF_INET6)
+ addattr_l(&req->n, datalen, RTA_PREFSRC,
&src.ipv6, bytelen);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Setting source");
}
if (rta->rta_len > RTA_LENGTH(0))
- addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH,
+ addattr_l(&req->n, datalen, RTA_MULTIPATH,
RTA_DATA(rta), RTA_PAYLOAD(rta));
}
/* If there is no useful nexthop then return. */
if (nexthop_num == 0) {
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath(): No useful nexthop.");
- return 0;
+ zlog_debug("%s: No useful nexthop.", __func__);
}
-skip:
- /* Talk to netlink socket. */
- return netlink_talk_info(netlink_talk_filter, &req.n,
- dplane_ctx_get_ns(ctx), 0);
+ return req->n.nlmsg_len;
}
int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
@@ -1982,6 +1995,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
addattr32(&req.n, req_size, NHA_ID, id);
if (cmd == RTM_NEWNEXTHOP) {
+ /*
+ * We distinguish between a "group", which is a collection
+ * of ids, and a singleton nexthop with an id. The
+ * group is installed as an id that just refers to a list of
+ * other ids.
+ */
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
_netlink_nexthop_build_group(
&req.n, req_size, id,
@@ -2068,14 +2087,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
}
}
- nexthop_done:
- if (IS_ZEBRA_DEBUG_KERNEL) {
- char buf[NEXTHOP_STRLEN];
+nexthop_done:
- snprintfrr(buf, sizeof(buf), "%pNHv", nh);
- zlog_debug("%s: ID (%u): %s (%u) %s ", __func__,
- id, buf, nh->vrf_id, label_buf);
- }
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: ID (%u): %pNHv vrf %s(%u) %s ",
+ __func__, id, nh,
+ vrf_id_to_name(nh->vrf_id),
+ nh->vrf_id, label_buf);
}
req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
@@ -2088,7 +2106,9 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
return -1;
}
- _netlink_nexthop_debug(cmd, id);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd),
+ id);
return netlink_talk_info(netlink_talk_filter, &req.n,
dplane_ctx_get_ns(ctx), 0);
@@ -2103,43 +2123,19 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
*/
enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
{
+ enum dplane_op_e op;
int cmd = 0;
int ret = 0;
- switch (dplane_ctx_get_op(ctx)) {
- case DPLANE_OP_NH_DELETE:
- cmd = RTM_DELNEXTHOP;
- break;
- case DPLANE_OP_NH_INSTALL:
- case DPLANE_OP_NH_UPDATE:
+ op = dplane_ctx_get_op(ctx);
+ if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
cmd = RTM_NEWNEXTHOP;
- break;
- case DPLANE_OP_ROUTE_INSTALL:
- case DPLANE_OP_ROUTE_UPDATE:
- case DPLANE_OP_ROUTE_DELETE:
- case DPLANE_OP_ROUTE_NOTIFY:
- case DPLANE_OP_LSP_INSTALL:
- case DPLANE_OP_LSP_UPDATE:
- case DPLANE_OP_LSP_DELETE:
- case DPLANE_OP_LSP_NOTIFY:
- case DPLANE_OP_PW_INSTALL:
- case DPLANE_OP_PW_UNINSTALL:
- case DPLANE_OP_SYS_ROUTE_ADD:
- case DPLANE_OP_SYS_ROUTE_DELETE:
- case DPLANE_OP_ADDR_INSTALL:
- case DPLANE_OP_ADDR_UNINSTALL:
- case DPLANE_OP_MAC_INSTALL:
- case DPLANE_OP_MAC_DELETE:
- case DPLANE_OP_NEIGH_INSTALL:
- case DPLANE_OP_NEIGH_UPDATE:
- case DPLANE_OP_NEIGH_DELETE:
- case DPLANE_OP_VTEP_ADD:
- case DPLANE_OP_VTEP_DELETE:
- case DPLANE_OP_NONE:
- flog_err(
- EC_ZEBRA_NHG_FIB_UPDATE,
- "Context received for kernel nexthop update with incorrect OP code (%u)",
- dplane_ctx_get_op(ctx));
+ else if (op == DPLANE_OP_NH_DELETE)
+ cmd = RTM_DELNEXTHOP;
+ else {
+ flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
+ "Context received for kernel nexthop update with incorrect OP code (%u)",
+ op);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
@@ -2158,6 +2154,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
int cmd, ret;
const struct prefix *p = dplane_ctx_get_dest(ctx);
struct nexthop *nexthop;
+ uint8_t nl_pkt[NL_PKT_BUF_SIZE];
if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
cmd = RTM_DELROUTE;
@@ -2178,9 +2175,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
* the kernel the old non-system route
*/
if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
- !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
- (void)netlink_route_multipath(RTM_DELROUTE,
- ctx);
+ !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
+ netlink_route_multipath(RTM_DELROUTE, ctx,
+ nl_pkt, sizeof(nl_pkt),
+ false);
+ netlink_talk_info(netlink_talk_filter,
+ (struct nlmsghdr *)nl_pkt,
+ dplane_ctx_get_ns(ctx), 0);
+ }
} else {
/*
* So v6 route replace semantics are not in
@@ -2194,9 +2196,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
* of the route delete. If that happens yeah we're
* screwed.
*/
- if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
- (void)netlink_route_multipath(RTM_DELROUTE,
- ctx);
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
+ netlink_route_multipath(RTM_DELROUTE, ctx,
+ nl_pkt, sizeof(nl_pkt),
+ false);
+ netlink_talk_info(netlink_talk_filter,
+ (struct nlmsghdr *)nl_pkt,
+ dplane_ctx_get_ns(ctx), 0);
+ }
cmd = RTM_NEWROUTE;
}
@@ -2204,9 +2211,13 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
- ret = netlink_route_multipath(cmd, ctx);
- else
+ if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
+ netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt),
+ false);
+ ret = netlink_talk_info(netlink_talk_filter,
+ (struct nlmsghdr *)nl_pkt,
+ dplane_ctx_get_ns(ctx), 0);
+ } else
ret = 0;
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
/* Update installed nexthops to signal which have been
@@ -2481,7 +2492,7 @@ static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type)
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
req.nhm.nh_family = family;
- return netlink_request(&zns->netlink_cmd, &req.n);
+ return netlink_request(&zns->netlink_cmd, &req);
}
@@ -2528,44 +2539,95 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
addr, lla, llalen, ns_id);
}
-/*
- * Add remote VTEP to the flood list for this VxLAN interface (VNI). This
- * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
+/**
+ * netlink_update_neigh_ctx_internal() - Common helper api for evpn
+ * neighbor updates using dataplane context object.
+ * @ctx: Dataplane context
+ * @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
+ * @mac: A neighbor cache link layer address
+ * @ip: A neighbor cache n/w layer destination address
+ * @replace_obj: Whether NEW request should replace existing object or
+ * add to the end of the list
+ * @family: AF_* netlink family
+ * @type: RTN_* route type
+ * @flags: NTF_* flags
+ * @state: NUD_* states
+ * @data: data buffer pointer
+ * @datalen: total amount of data buffer space
+ *
+ * Return: Result status
*/
-static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
- int cmd)
+static ssize_t
+netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx,
+ int cmd, const struct ethaddr *mac,
+ const struct ipaddr *ip, bool replace_obj,
+ uint8_t family, uint8_t type, uint8_t flags,
+ uint16_t state, void *data, size_t datalen)
{
uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
- char buf[256];
- } req;
- uint8_t dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
- const struct ipaddr *addr;
+ char buf[];
+ } *req = data;
+ int ipa_len;
+ enum dplane_op_e op;
- memset(&req, 0, sizeof(req));
+ memset(req, 0, datalen);
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST;
+ op = dplane_ctx_get_op(ctx);
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
- req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND);
- req.n.nlmsg_type = cmd;
- req.ndm.ndm_family = PF_BRIDGE;
- req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT;
- req.ndm.ndm_flags |= NTF_SELF; /* Handle by "self", not "master" */
+ req->n.nlmsg_flags |=
+ NLM_F_CREATE
+ | (replace_obj ? NLM_F_REPLACE : NLM_F_APPEND);
+ req->n.nlmsg_type = cmd;
+ req->ndm.ndm_family = family;
+ req->ndm.ndm_type = type;
+ req->ndm.ndm_state = state;
+ req->ndm.ndm_flags = flags;
+ req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
+
+ addattr_l(&req->n, sizeof(req),
+ NDA_PROTOCOL, &protocol, sizeof(protocol));
+ if (mac)
+ addattr_l(&req->n, datalen, NDA_LLADDR, mac, 6);
+ ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
+ addattr_l(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len);
- addattr_l(&req.n, sizeof(req),
- NDA_PROTOCOL, &protocol, sizeof(protocol));
- addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6);
- req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
+ if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
+ vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
- addr = dplane_ctx_neigh_get_ipaddr(ctx);
+ if (vid > 0)
+ addattr16(&req->n, datalen, NDA_VLAN, vid);
- addattr_l(&req.n, sizeof(req), NDA_DST, &(addr->ipaddr_v4), 4);
+ addattr32(&req->n, datalen, NDA_MASTER,
+ dplane_ctx_mac_get_br_ifindex(ctx));
+ }
- return netlink_talk_info(netlink_talk_filter, &req.n,
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+/*
+ * Add remote VTEP to the flood list for this VxLAN interface (VNI). This
+ * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
+ */
+static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
+ int cmd)
+{
+ struct ethaddr dst_mac = {.octet = {0}};
+ uint8_t nl_pkt[NL_PKT_BUF_SIZE];
+
+ netlink_update_neigh_ctx_internal(
+ ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
+ PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt,
+ sizeof(nl_pkt));
+
+ return netlink_talk_info(netlink_talk_filter,
+ (struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
}
@@ -2760,7 +2822,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family,
if (master_ifindex)
addattr32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex);
- return netlink_request(netlink_cmd, &req.n);
+ return netlink_request(netlink_cmd, &req);
}
/*
@@ -2856,12 +2918,14 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns,
addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: Tx family %s IF %s(%u) MAC %s vid %u", __func__,
- nl_family_to_str(req.ndm.ndm_family), br_if->name,
- br_if->ifindex,
- prefix_mac2str(mac, buf, sizeof(buf)), vid);
+ zlog_debug(
+ "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %s vid %u",
+ __func__, nl_family_to_str(req.ndm.ndm_family),
+ br_if->name, br_if->ifindex,
+ vrf_id_to_name(br_if->vrf_id), br_if->vrf_id,
+ prefix_mac2str(mac, buf, sizeof(buf)), vid);
- return netlink_request(&zns->netlink_cmd, &req.n);
+ return netlink_request(&zns->netlink_cmd, &req);
}
int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
@@ -2890,92 +2954,60 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
/*
* Netlink-specific handler for MAC updates using dataplane context object.
*/
-static enum zebra_dplane_result
-netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx)
+ssize_t
+netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
+ size_t datalen)
{
- uint8_t protocol = RTPROT_ZEBRA;
- struct {
- struct nlmsghdr n;
- struct ndmsg ndm;
- char buf[256];
- } req;
- int ret;
- int dst_alen;
- int vid_present = 0;
- int cmd;
- struct in_addr vtep_ip;
+ struct ipaddr vtep_ip;
vlanid_t vid;
+ ssize_t total;
+ int cmd;
+ uint8_t flags;
+ uint16_t state;
+ uint8_t nl_pkt[NL_PKT_BUF_SIZE];
- if (dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL)
- cmd = RTM_NEWNEIGH;
- else
- cmd = RTM_DELNEIGH;
-
- memset(&req, 0, sizeof(req));
+ cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
+ ? RTM_NEWNEIGH : RTM_DELNEIGH;
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- if (cmd == RTM_NEWNEIGH)
- req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
- req.n.nlmsg_type = cmd;
- req.ndm.ndm_family = AF_BRIDGE;
- req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
- req.ndm.ndm_state = NUD_REACHABLE;
+ flags = (NTF_SELF | NTF_MASTER);
+ state = NUD_REACHABLE;
if (dplane_ctx_mac_is_sticky(ctx))
- req.ndm.ndm_state |= NUD_NOARP;
+ state |= NUD_NOARP;
else
- req.ndm.ndm_flags |= NTF_EXT_LEARNED;
-
- addattr_l(&req.n, sizeof(req),
- NDA_PROTOCOL, &protocol, sizeof(protocol));
- addattr_l(&req.n, sizeof(req), NDA_LLADDR,
- dplane_ctx_mac_get_addr(ctx), 6);
- req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
-
- dst_alen = 4; // TODO: hardcoded
- vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx));
- addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen);
+ flags |= NTF_EXT_LEARNED;
- vid = dplane_ctx_mac_get_vlan(ctx);
-
- if (vid > 0) {
- addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
- vid_present = 1;
- }
- addattr32(&req.n, sizeof(req), NDA_MASTER,
- dplane_ctx_mac_get_br_ifindex(ctx));
+ vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx));
+ SET_IPADDR_V4(&vtep_ip);
if (IS_ZEBRA_DEBUG_KERNEL) {
char ipbuf[PREFIX_STRLEN];
char buf[ETHER_ADDR_STRLEN];
- char dst_buf[PREFIX_STRLEN + 10];
char vid_buf[20];
- if (vid_present)
+ vid = dplane_ctx_mac_get_vlan(ctx);
+ if (vid > 0)
snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
else
vid_buf[0] = '\0';
- inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf));
- snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf);
- prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf, sizeof(buf));
+ const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx);
- zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s",
- nl_msg_type_to_str(cmd),
- nl_family_to_str(req.ndm.ndm_family),
+ zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s",
+ nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
dplane_ctx_get_ifname(ctx),
dplane_ctx_get_ifindex(ctx), vid_buf,
dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
- buf, dst_buf);
+ prefix_mac2str(mac, buf, sizeof(buf)),
+ ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)));
}
- ret = netlink_talk_info(netlink_talk_filter, &req.n,
- dplane_ctx_get_ns(ctx), 0);
- if (ret == 0)
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
- else
- return ZEBRA_DPLANE_REQUEST_FAILURE;
+ total = netlink_update_neigh_ctx_internal(
+ ctx, cmd, dplane_ctx_mac_get_addr(ctx),
+ dplane_ctx_neigh_get_ipaddr(ctx), true, AF_BRIDGE, 0,
+ flags, state, nl_pkt, sizeof(nl_pkt));
+
+ return total;
}
/*
@@ -3017,6 +3049,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
struct interface *link_if;
struct ethaddr mac;
struct ipaddr ip;
+ struct vrf *vrf;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
int mac_present = 0;
@@ -3031,6 +3064,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (!ifp || !ifp->info)
return 0;
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
zif = (struct zebra_if *)ifp->info;
/* Parse attributes and extract fields of interest. */
@@ -3038,10 +3072,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
if (!tb[NDA_DST]) {
- zlog_debug("%s family %s IF %s(%u) - no DST",
+ zlog_debug("%s family %s IF %s(%u) vrf %s(%u) - no DST",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex);
+ ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id);
return 0;
}
@@ -3093,12 +3127,13 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
+ "%s family %s IF %s(%u) vrf %s(%u) - LLADDR is not MAC, len %lu",
nl_msg_type_to_str(
h->nlmsg_type),
nl_family_to_str(
ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
+ VRF_LOGNAME(vrf), ifp->vrf_id,
(unsigned long)RTA_PAYLOAD(
tb[NDA_LLADDR]));
return 0;
@@ -3113,10 +3148,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
+ "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex,
+ ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id,
ipaddr2str(&ip, buf2, sizeof(buf2)),
mac_present
? prefix_mac2str(&mac, buf, sizeof(buf))
@@ -3138,10 +3173,10 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
}
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Rx %s family %s IF %s(%u) IP %s",
+ zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %s",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(ndm->ndm_family), ifp->name,
- ndm->ndm_ifindex,
+ ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id,
ipaddr2str(&ip, buf2, sizeof(buf2)));
/* Process the delete - it may result in re-adding the neighbor if it is
@@ -3190,7 +3225,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family,
if (ifindex)
addattr32(&req.n, sizeof(req), NDA_IFINDEX, ifindex);
- return netlink_request(netlink_cmd, &req.n);
+ return netlink_request(netlink_cmd, &req);
}
/*
@@ -3278,7 +3313,7 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns,
ipaddr2str(ip, buf, sizeof(buf)), req.n.nlmsg_flags);
}
- return netlink_request(&zns->netlink_cmd, &req.n);
+ return netlink_request(&zns->netlink_cmd, &req);
}
int netlink_neigh_read_specific_ip(struct ipaddr *ip,
@@ -3295,9 +3330,10 @@ int netlink_neigh_read_specific_ip(struct ipaddr *ip,
zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: neigh request IF %s(%u) IP %s vrf_id %u",
+ zlog_debug("%s: neigh request IF %s(%u) IP %s vrf %s(%u)",
__func__, vlan_if->name, vlan_if->ifindex,
- ipaddr2str(ip, buf, sizeof(buf)), vlan_if->vrf_id);
+ ipaddr2str(ip, buf, sizeof(buf)),
+ vrf_id_to_name(vlan_if->vrf_id), vlan_if->vrf_id);
ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip,
vlan_if->ifindex);
@@ -3355,21 +3391,12 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
int cmd)
{
- uint8_t protocol = RTPROT_ZEBRA;
- struct {
- struct nlmsghdr n;
- struct ndmsg ndm;
- char buf[256];
- } req;
- int ipa_len;
- char buf[INET6_ADDRSTRLEN];
- char buf2[ETHER_ADDR_STRLEN];
const struct ipaddr *ip;
const struct ethaddr *mac;
uint8_t flags;
uint16_t state;
-
- memset(&req, 0, sizeof(req));
+ uint8_t family;
+ uint8_t nl_pkt[NL_PKT_BUF_SIZE];
ip = dplane_ctx_neigh_get_ipaddr(ctx);
mac = dplane_ctx_neigh_get_mac(ctx);
@@ -3379,36 +3406,26 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- if (cmd == RTM_NEWNEIGH)
- req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
- req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
- req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
- req.ndm.ndm_state = state;
- req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
- req.ndm.ndm_type = RTN_UNICAST;
- req.ndm.ndm_flags = flags;
+ family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
- addattr_l(&req.n, sizeof(req),
- NDA_PROTOCOL, &protocol, sizeof(protocol));
- ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
- addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
- if (mac)
- addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ char buf[INET6_ADDRSTRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
- nl_msg_type_to_str(cmd),
- nl_family_to_str(req.ndm.ndm_family),
- dplane_ctx_get_ifname(ctx),
- dplane_ctx_get_ifindex(ctx),
- ipaddr2str(ip, buf, sizeof(buf)),
- mac ? prefix_mac2str(mac, buf2, sizeof(buf2))
- : "null",
- flags, state);
+ zlog_debug(
+ "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
+ nl_msg_type_to_str(cmd), nl_family_to_str(family),
+ dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
+ ipaddr2str(ip, buf, sizeof(buf)),
+ mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) : "null",
+ flags, state);
+ }
- return netlink_talk_info(netlink_talk_filter, &req.n,
+ netlink_update_neigh_ctx_internal(
+ ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags,
+ state, nl_pkt, sizeof(nl_pkt));
+
+ return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
}
@@ -3417,7 +3434,18 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
*/
enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
{
- return netlink_macfdb_update_ctx(ctx);
+ uint8_t nl_pkt[NL_PKT_BUF_SIZE];
+ ssize_t rv;
+
+ rv = netlink_macfdb_update_ctx(ctx, nl_pkt, sizeof(nl_pkt));
+ if (rv <= 0)
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ rv = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
+ dplane_ctx_get_ns(ctx), 0);
+
+ return rv == 0 ?
+ ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE;
}
enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 2b4b145149..d6a993e78a 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -66,6 +66,12 @@ void rt_netlink_init(void);
/* MPLS label forwarding table change, using dataplane context information. */
extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx);
+extern ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
+ uint8_t *data, size_t datalen,
+ bool fpm);
+extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx,
+ uint8_t *data, size_t datalen);
+
extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_route_read(struct zebra_ns *zns);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 60ac471b5a..11434edfcf 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -46,6 +46,10 @@
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "zebra/rtadv_clippy.c"
+#endif
+
extern struct zebra_privs_t zserv_privs;
#if defined(HAVE_RTADV)
@@ -204,9 +208,12 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
}
/* Logging of packet. */
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Tx RA, socket %u", ifp->name, ifp->ifindex,
- sock);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
/* Fill in sockaddr_in6. */
memset(&addr, 0, sizeof(struct sockaddr_in6));
@@ -227,7 +234,7 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
rtadv->nd_ra_code = 0;
rtadv->nd_ra_cksum = 0;
- rtadv->nd_ra_curhoplimit = 64;
+ rtadv->nd_ra_curhoplimit = zif->rtadv.AdvCurHopLimit;
/* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0
@@ -333,16 +340,6 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix,
&rprefix->prefix.prefix);
-#ifdef DEBUG
- {
- uint8_t buf[INET6_ADDRSTRLEN];
-
- zlog_debug("DEBUG %s",
- inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
- buf, INET6_ADDRSTRLEN));
- }
-#endif /* DEBUG */
-
len += sizeof(struct nd_opt_prefix_info);
}
@@ -388,9 +385,11 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
if (len + opt_len > max_len) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
zlog_warn(
- "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it",
- ifp->name, ifp->ifindex);
+ "%s(%s:%u): Tx RA: RDNSS option would exceed MTU, omitting it",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex);
goto no_more_opts;
}
struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
@@ -510,10 +509,17 @@ static int rtadv_timer(struct thread *thread)
<= 0)
zif->rtadv.inFastRexmit = 0;
- if (IS_ZEBRA_DEBUG_SEND)
+ if (IS_ZEBRA_DEBUG_SEND) {
+ struct vrf *vrf =
+ vrf_lookup_by_id(
+ ifp->vrf_id);
+
zlog_debug(
- "Fast RA Rexmit on interface %s",
- ifp->name);
+ "Fast RA Rexmit on interface %s(%s:%u)",
+ ifp->name,
+ VRF_LOGNAME(vrf),
+ ifp->ifindex);
+ }
rtadv_send_packet(rtadv_get_socket(zvrf),
ifp, RA_ENABLE);
@@ -612,9 +618,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
if (len < sizeof(struct nd_router_advert)) {
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
- ifp->name, ifp->ifindex, len, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with invalid length %d from %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len,
+ addr_str);
+ }
return;
}
@@ -622,9 +633,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
rtadv_process_optional(msg + sizeof(struct nd_router_advert),
len - sizeof(struct nd_router_advert),
ifp, addr);
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s",
- ifp->name, ifp->ifindex, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with non-linklocal source address from %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex,
+ addr_str);
+ }
return;
}
@@ -703,9 +719,12 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
return;
}
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
- ifp->ifindex, len, addr_str);
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, len, addr_str);
+ }
if (if_is_loopback(ifp)
|| CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
@@ -718,8 +737,11 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
/* ICMP message length check. */
if (len < sizeof(struct icmp6_hdr)) {
- zlog_debug("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
- ifp->name, ifp->ifindex, len);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug(
+ "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len);
return;
}
@@ -728,15 +750,20 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
/* ICMP message type check. */
if (icmph->icmp6_type != ND_ROUTER_SOLICIT
&& icmph->icmp6_type != ND_ROUTER_ADVERT) {
- zlog_debug("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
- ifp->name, ifp->ifindex, icmph->icmp6_type);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex,
+ icmph->icmp6_type);
return;
}
/* Hoplimit check. */
if (hoplimit >= 0 && hoplimit != 255) {
- zlog_debug("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
- ifp->ifindex, hoplimit);
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+ zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name,
+ VRF_LOGNAME(vrf), ifp->ifindex, hoplimit);
return;
}
@@ -1055,25 +1082,34 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
unsigned int ra_interval = ra_interval_rxd;
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%u: IF %u RA %s from client %s, interval %ums",
- zvrf_id(zvrf), ifindex,
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s:%u: IF %u RA %s from client %s, interval %ums",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
enable ? "enable" : "disable",
zebra_route_string(client->proto), ra_interval);
+ }
/* Locate interface and check VRF match. */
ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (!ifp) {
+ struct vrf *vrf = zvrf->vrf;
+
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
- "%u: IF %u RA %s client %s - interface unknown",
- zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
+ "%s:%u: IF %u RA %s client %s - interface unknown",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
+ enable ? "enable" : "disable",
zebra_route_string(client->proto));
return;
}
if (ifp->vrf_id != zvrf_id(zvrf)) {
+ struct vrf *vrf = zvrf->vrf;
+
zlog_debug(
- "%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
- zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
+ "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
+ enable ? "enable" : "disable",
zebra_route_string(client->proto), ifp->vrf_id);
return;
}
@@ -1199,6 +1235,53 @@ DEFUN (no_ipv6_nd_ra_fast_retrans,
return CMD_SUCCESS;
}
+DEFPY (ipv6_nd_ra_hop_limit,
+ ipv6_nd_ra_hop_limit_cmd,
+ "ipv6 nd ra-hop-limit (0-255)$hopcount",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Advertisement Hop Limit\n"
+ "Advertisement Hop Limit in hops (default:64)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+
+ if (if_is_loopback(ifp)
+ || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+ vty_out(vty,
+ "Cannot configure IPv6 Router Advertisements on this interface\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ zif->rtadv.AdvCurHopLimit = hopcount;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ipv6_nd_ra_hop_limit,
+ no_ipv6_nd_ra_hop_limit_cmd,
+ "no ipv6 nd ra-hop-limit [(0-255)]",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Advertisement Hop Limit\n"
+ "Advertisement Hop Limit in hops\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+
+ if (if_is_loopback(ifp)
+ || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+ vty_out(vty,
+ "Cannot configure IPv6 Router Advertisements on this interface\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ipv6_nd_suppress_ra,
ipv6_nd_suppress_ra_cmd,
"ipv6 nd suppress-ra",
@@ -2146,6 +2229,8 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp)
vty_out(vty,
" ND advertised retransmit interval is %d milliseconds\n",
rtadv->AdvRetransTimer);
+ vty_out(vty, " ND advertised hop-count limit is %d hops\n",
+ rtadv->AdvCurHopLimit);
vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
zif->ra_sent, zif->ra_rcvd);
interval = rtadv->MaxRtrAdvInterval;
@@ -2237,6 +2322,10 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
if (!zif->rtadv.UseFastRexmit)
vty_out(vty, " no ipv6 nd ra-fast-retrans\n");
+ if (zif->rtadv.AdvCurHopLimit != RTADV_DEFAULT_HOPLIMIT)
+ vty_out(vty, " ipv6 nd ra-hop-limit %d\n",
+ zif->rtadv.AdvCurHopLimit);
+
if (zif->rtadv.AdvDefaultLifetime != -1)
vty_out(vty, " ipv6 nd ra-lifetime %d\n",
zif->rtadv.AdvDefaultLifetime);
@@ -2329,6 +2418,13 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
struct rtadv *rtadv = &zvrf->rtadv;
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s(%s) with event: %d and val: %d", __func__,
+ VRF_LOGNAME(vrf), event, val);
+ }
+
switch (event) {
case RTADV_START:
thread_add_read(zrouter.master, rtadv_read, zvrf, val,
@@ -2371,20 +2467,26 @@ void rtadv_init(struct zebra_vrf *zvrf)
}
}
-void rtadv_terminate(struct zebra_vrf *zvrf)
+void rtadv_vrf_terminate(struct zebra_vrf *zvrf)
{
rtadv_event(zvrf, RTADV_STOP, 0);
if (zvrf->rtadv.sock >= 0) {
close(zvrf->rtadv.sock);
zvrf->rtadv.sock = -1;
- } else if (zrouter.rtadv_sock >= 0) {
- close(zrouter.rtadv_sock);
- zrouter.rtadv_sock = -1;
}
+
zvrf->rtadv.adv_if_count = 0;
zvrf->rtadv.adv_msec_if_count = 0;
}
+void rtadv_terminate(void)
+{
+ if (zrouter.rtadv_sock >= 0) {
+ close(zrouter.rtadv_sock);
+ zrouter.rtadv_sock = -1;
+ }
+}
+
void rtadv_cmd_init(void)
{
hook_register(zebra_if_extra_info, nd_dump_vty);
@@ -2392,6 +2494,8 @@ void rtadv_cmd_init(void)
install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd);
+ install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_nd_ra_hop_limit_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
@@ -2445,10 +2549,13 @@ static int if_join_all_router(int sock, struct interface *ifp)
ifp->name, ifp->ifindex, sock,
safe_strerror(errno));
- if (IS_ZEBRA_DEBUG_EVENT)
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
zlog_debug(
- "%s(%u): Join All-Routers multicast group, socket %u",
- ifp->name, ifp->ifindex, sock);
+ "%s(%s:%u): Join All-Routers multicast group, socket %u",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
return 0;
}
@@ -2465,17 +2572,22 @@ static int if_leave_all_router(int sock, struct interface *ifp)
ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
sizeof(mreq));
- if (ret < 0)
+ if (ret < 0) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
flog_err_sys(
EC_LIB_SOCKET,
- "%s(%u): Failed to leave group, socket %u error %s",
- ifp->name, ifp->ifindex, sock, safe_strerror(errno));
+ "%s(%s:%u): Failed to leave group, socket %u error %s",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock,
+ safe_strerror(errno));
+ }
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug(
- "%s(%u): Leave All-Routers multicast group, socket %u",
- ifp->name, ifp->ifindex, sock);
-
+ "%s(%s:%u): Leave All-Routers multicast group, socket %u",
+ ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock);
+ }
return 0;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 64b28cbfd6..68a5bbcdbe 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -153,7 +153,8 @@ typedef enum {
} ipv6_nd_suppress_ra_status;
extern void rtadv_init(struct zebra_vrf *zvrf);
-extern void rtadv_terminate(struct zebra_vrf *zvrf);
+extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf);
+extern void rtadv_terminate(void);
extern void rtadv_stop_ra(struct interface *ifp);
extern void rtadv_stop_ra_all(void);
extern void rtadv_cmd_init(void);
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index c9699c7d95..a5a605f27e 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -174,11 +174,40 @@ enum zebra_dplane_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
}
/*
+ * Update specified rule for a specific interface.
+ */
+enum zebra_dplane_result kernel_update_pbr_rule(struct zebra_pbr_rule *old_rule,
+ struct zebra_pbr_rule *new_rule)
+{
+ int ret = 0;
+
+ /* Add the new, updated one */
+ ret = netlink_rule_update(RTM_NEWRULE, new_rule);
+
+ /**
+ * Delete the old one.
+ *
+ * Don't care about this result right?
+ */
+ netlink_rule_update(RTM_DELRULE, old_rule);
+
+ kernel_pbr_rule_add_del_status(new_rule,
+ (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
+ : ZEBRA_DPLANE_INSTALL_FAILURE);
+
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
+/*
* Handle netlink notification informing a rule add or delete.
* Handling of an ADD is TBD.
* DELs are notified up, if other attributes indicate it may be a
* notification of interest. The expectation is that if this corresponds
* to a PBR rule added by FRR, it will be readded.
+ *
+ * If startup and we see a rule we created, delete it as its leftover
+ * from a previous instance and should have been removed on shutdown.
+ *
*/
int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
@@ -190,15 +219,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
struct zebra_pbr_rule rule = {};
char buf1[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
+ uint8_t proto = 0;
/* Basic validation followed by extracting attributes. */
if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
return 0;
- /* TBD */
- if (h->nlmsg_type == RTM_NEWRULE)
- return 0;
-
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
if (len < 0) {
zlog_err(
@@ -222,19 +248,6 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
memset(tb, 0, sizeof(tb));
netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
- /* TBD: We don't care about rules not specifying an IIF. */
- if (tb[FRA_IFNAME] == NULL)
- return 0;
-
- ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
- zns = zebra_ns_lookup(ns_id);
-
- /* If we don't know the interface, we don't care. */
- if (!if_lookup_by_name_per_ns(zns, ifname))
- return 0;
-
- strlcpy(rule.ifname, ifname, sizeof(rule.ifname));
-
if (tb[FRA_PRIORITY])
rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
@@ -246,6 +259,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
memcpy(&rule.rule.filter.src_ip.u.prefix6,
RTA_DATA(tb[FRA_SRC]), 16);
rule.rule.filter.src_ip.prefixlen = frh->src_len;
+ rule.rule.filter.src_ip.family = frh->family;
rule.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
}
@@ -257,6 +271,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
memcpy(&rule.rule.filter.dst_ip.u.prefix6,
RTA_DATA(tb[FRA_DST]), 16);
rule.rule.filter.dst_ip.prefixlen = frh->dst_len;
+ rule.rule.filter.dst_ip.family = frh->family;
rule.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
}
@@ -265,6 +280,49 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
else
rule.rule.action.table = frh->table;
+ /* TBD: We don't care about rules not specifying an IIF. */
+ if (tb[FRA_IFNAME] == NULL)
+ return 0;
+
+ if (tb[FRA_PROTOCOL])
+ proto = *(uint8_t *)RTA_DATA(tb[FRA_PROTOCOL]);
+
+ ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
+ strlcpy(rule.ifname, ifname, sizeof(rule.ifname));
+
+ if (h->nlmsg_type == RTM_NEWRULE) {
+ /*
+ * If we see a rule at startup we created, delete it now.
+ * It should have been flushed on a previous shutdown.
+ */
+ if (startup && proto == RTPROT_ZEBRA) {
+ int ret;
+
+ ret = netlink_rule_update(RTM_DELRULE, &rule);
+
+ zlog_debug(
+ "%s: %s leftover rule: family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
+ __func__,
+ ((ret == 0) ? "Removed" : "Failed to remove"),
+ nl_family_to_str(frh->family), rule.ifname,
+ rule.rule.ifindex, rule.rule.priority,
+ prefix2str(&rule.rule.filter.src_ip, buf1,
+ sizeof(buf1)),
+ prefix2str(&rule.rule.filter.dst_ip, buf2,
+ sizeof(buf2)),
+ rule.rule.action.table);
+ }
+
+ /* TBD */
+ return 0;
+ }
+
+ zns = zebra_ns_lookup(ns_id);
+
+ /* If we don't know the interface, we don't care. */
+ if (!if_lookup_by_name_per_ns(zns, ifname))
+ return 0;
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
@@ -281,12 +339,51 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
}
/*
+ * Request rules from the kernel
+ */
+static int netlink_request_rules(struct zebra_ns *zns, int family, int type)
+{
+ struct {
+ struct nlmsghdr n;
+ struct fib_rule_hdr frh;
+ char buf[NL_PKT_BUF_SIZE];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = type;
+ req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
+ req.frh.family = family;
+
+ return netlink_request(&zns->netlink_cmd, &req);
+}
+
+/*
* Get to know existing PBR rules in the kernel - typically called at startup.
- * TBD.
*/
int netlink_rules_read(struct zebra_ns *zns)
{
- return 0;
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true);
+
+ ret = netlink_request_rules(zns, AF_INET, RTM_GETRULE);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
+ &dp_info, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_request_rules(zns, AF_INET6, RTM_GETRULE);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
+ &dp_info, 0, 1);
+ return ret;
}
#endif /* HAVE_NETLINK */
diff --git a/zebra/rule_socket.c b/zebra/rule_socket.c
index e2c650b4ad..219fa7de6f 100644
--- a/zebra/rule_socket.c
+++ b/zebra/rule_socket.c
@@ -57,4 +57,12 @@ enum zebra_dplane_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
+enum zebra_dplane_result kernel_update_pbr_rule(struct zebra_pbr_rule *old_rule,
+ struct zebra_pbr_rule *new_rule)
+{
+ flog_err(EC_LIB_UNAVAILABLE, "%s not Implemented for this platform",
+ __PRETTY_FUNCTION__);
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+}
+
#endif
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 1d49de5410..aafb4abb01 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -101,6 +101,10 @@ zebra_zebra_SOURCES = \
zebra/zebra_netns_notify.c \
zebra/table_manager.c \
zebra/zapi_msg.c \
+ zebra/zebra_nb.c \
+ zebra/zebra_nb_config.c \
+ zebra/zebra_nb_rpcs.c \
+ zebra/zebra_nb_state.c \
zebra/zebra_errors.c \
zebra/zebra_gr.c \
# end
@@ -119,6 +123,9 @@ zebra/zebra_vty.$(OBJEXT): zebra/zebra_vty_clippy.c
zebra/zebra_routemap_clippy.c: $(CLIPPY_DEPS)
zebra/zebra_routemap.$(OBJEXT): zebra/zebra_routemap_clippy.c
+zebra/rtadv_clippy.c: $(CLIPPY_DEPS)
+zebra/rtadv.$(OBJEXT): zebra/rtadv_clippy.c
+
noinst_HEADERS += \
zebra/connected.h \
zebra/debug.h \
@@ -164,6 +171,7 @@ noinst_HEADERS += \
zebra/zebra_netns_notify.h \
zebra/table_manager.h \
zebra/zapi_msg.h \
+ zebra/zebra_nb.h \
zebra/zebra_errors.h \
# end
@@ -191,5 +199,19 @@ zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c
endif
endif
+nodist_zebra_zebra_SOURCES = \
+ yang/frr-zebra.yang.c \
+ # end
+
zebra_zebra_cumulus_mlag_la_SOURCES = zebra/zebra_mlag_private.c
zebra_zebra_cumulus_mlag_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+
+if LINUX
+module_LTLIBRARIES += zebra/dplane_fpm_nl.la
+
+zebra_dplane_fpm_nl_la_SOURCES = zebra/dplane_fpm_nl.c
+zebra_dplane_fpm_nl_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+zebra_dplane_fpm_nl_la_LIBADD =
+
+vtysh_scan += $(top_srcdir)/zebra/dplane_fpm_nl.c
+endif
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 2190bfab4f..092b5dd3c2 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -957,7 +957,6 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
/* Send response to a get label chunk request to client */
int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
- uint8_t proto, uint16_t instance,
struct label_manager_chunk *lmc)
{
int ret;
@@ -965,9 +964,9 @@ int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,
zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
/* proto */
- stream_putc(s, proto);
+ stream_putc(s, client->proto);
/* instance */
- stream_putw(s, instance);
+ stream_putw(s, client->instance);
if (lmc) {
/* keep */
@@ -1413,6 +1412,132 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
}
}
+/*
+ * Create a new nexthop based on a zapi nexthop.
+ */
+static struct nexthop *nexthop_from_zapi(struct route_entry *re,
+ const struct zapi_nexthop *api_nh,
+ const struct zapi_route *api)
+{
+ struct nexthop *nexthop = NULL;
+ struct ipaddr vtep_ip;
+ struct interface *ifp;
+ char nhbuf[INET6_ADDRSTRLEN] = "";
+
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ nexthop = nexthop_from_ifindex(api_nh->ifindex, api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
+ nhbuf, api_nh->vrf_id);
+ }
+ nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, NULL,
+ api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
+ __func__, nhbuf, api_nh->vrf_id,
+ api_nh->ifindex);
+ }
+
+ nexthop = nexthop_from_ipv4_ifindex(
+ &api_nh->gate.ipv4, NULL, api_nh->ifindex,
+ api_nh->vrf_id);
+
+ ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id);
+ if (ifp && connected_is_unnumbered(ifp))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+
+ /* Special handling for IPv4 routes sourced from EVPN:
+ * the nexthop and associated MAC need to be installed.
+ */
+ if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ memset(&vtep_ip, 0, sizeof(struct ipaddr));
+ vtep_ip.ipa_type = IPADDR_V4;
+ memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4),
+ sizeof(struct in_addr));
+ zebra_vxlan_evpn_vrf_route_add(
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api->prefix);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
+ nhbuf, api_nh->vrf_id);
+ }
+ nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, api_nh->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
+ sizeof(nhbuf));
+ zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
+ __func__, nhbuf, api_nh->vrf_id,
+ api_nh->ifindex);
+ }
+ nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
+ api_nh->ifindex,
+ api_nh->vrf_id);
+
+ /* Special handling for IPv6 routes sourced from EVPN:
+ * the nexthop and associated MAC need to be installed.
+ */
+ if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ memset(&vtep_ip, 0, sizeof(struct ipaddr));
+ vtep_ip.ipa_type = IPADDR_V6;
+ memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
+ sizeof(struct in6_addr));
+ zebra_vxlan_evpn_vrf_route_add(
+ api_nh->vrf_id, &api_nh->rmac,
+ &vtep_ip, &api->prefix);
+ }
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: nh blackhole %d",
+ __func__, api_nh->bh_type);
+
+ nexthop = nexthop_from_blackhole(api_nh->bh_type);
+ break;
+ }
+
+ /* Return early if we couldn't process the zapi nexthop */
+ if (nexthop == NULL) {
+ goto done;
+ }
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
+ nexthop->weight = api_nh->weight;
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (api_nh->backup_idx < api->backup_nexthop_num) {
+ /* Capture backup info */
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nexthop->backup_idx = api_nh->backup_idx;
+ } else {
+ /* Warn about invalid backup index */
+ if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: invalid backup nh idx %d",
+ __func__, api_nh->backup_idx);
+ }
+ }
+done:
+ return nexthop;
+}
+
static void zread_route_add(ZAPI_HANDLER_ARGS)
{
struct stream *s;
@@ -1421,12 +1546,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
afi_t afi;
struct prefix_ipv6 *src_p = NULL;
struct route_entry *re;
- struct nexthop *nexthop = NULL;
+ struct nexthop *nexthop = NULL, *last_nh;
struct nexthop_group *ng = NULL;
+ struct nhg_backup_info *bnhg = NULL;
int i, ret;
vrf_id_t vrf_id;
- struct ipaddr vtep_ip;
- struct interface *ifp;
+ struct nhg_hash_entry nhe;
+ enum lsp_types_t label_type;
+ char nhbuf[NEXTHOP_STRLEN];
+ char labelbuf[MPLS_LABEL_STRLEN];
s = msg;
if (zapi_route_decode(s, &api) < 0) {
@@ -1440,8 +1568,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
char buf_prefix[PREFIX_STRLEN];
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: p=%s, flags=0x%x",
- __func__, buf_prefix, api.flags);
+ zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x",
+ __func__, buf_prefix, (int)api.message, api.flags);
}
/* Allocate new route. */
@@ -1469,6 +1597,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
return;
}
+ /* Report misuse of the backup flag */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) &&
+ api.backup_nexthop_num == 0) {
+ if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX",
+ __func__,
+ zebra_route_string(client->proto), &api.prefix);
+ }
+
/* Use temporary list of nexthops */
ng = nexthop_group_new();
@@ -1479,130 +1616,138 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
*/
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
- ifindex_t ifindex = 0;
- nexthop = NULL;
+ /* Convert zapi nexthop */
+ nexthop = nexthop_from_zapi(re, api_nh, &api);
+ if (!nexthop) {
+ flog_warn(
+ EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthops Specified: %d but we failed to properly create one",
+ __func__, api.nexthop_num);
+ nexthop_group_delete(&ng);
+ XFREE(MTYPE_RE, re);
+ return;
+ }
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("nh type %d", api_nh->type);
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
+ && api_nh->type != NEXTHOP_TYPE_IFINDEX
+ && api_nh->type != NEXTHOP_TYPE_BLACKHOLE
+ && api_nh->label_num > 0) {
- switch (api_nh->type) {
- case NEXTHOP_TYPE_IFINDEX:
- nexthop = nexthop_from_ifindex(api_nh->ifindex,
- api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV4:
- if (IS_ZEBRA_DEBUG_RECV) {
- char nhbuf[INET6_ADDRSTRLEN] = {0};
+ label_type = lsp_type_from_re_type(client->proto);
+ nexthop_add_labels(nexthop, label_type,
+ api_nh->label_num,
+ &api_nh->labels[0]);
+ }
- inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
- INET6_ADDRSTRLEN);
- zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
- nhbuf, api_nh->vrf_id);
- }
- nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4,
- NULL, api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (IS_ZEBRA_DEBUG_RECV) {
+ labelbuf[0] = '\0';
+ nhbuf[0] = '\0';
- memset(&vtep_ip, 0, sizeof(struct ipaddr));
- ifindex = api_nh->ifindex;
- if (IS_ZEBRA_DEBUG_RECV) {
- char nhbuf[INET6_ADDRSTRLEN] = {0};
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
- inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
- INET6_ADDRSTRLEN);
- zlog_debug(
- "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d",
- __func__, nhbuf, api_nh->vrf_id,
- re->vrf_id, ifindex);
- }
- nexthop = nexthop_from_ipv4_ifindex(
- &api_nh->gate.ipv4, NULL, ifindex,
- api_nh->vrf_id);
-
- ifp = if_lookup_by_index(ifindex, api_nh->vrf_id);
- if (ifp && connected_is_unnumbered(ifp))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
- /* Special handling for IPv4 routes sourced from EVPN:
- * the nexthop and associated MAC need to be installed.
- */
- if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
- vtep_ip.ipa_type = IPADDR_V4;
- memcpy(&(vtep_ip.ipaddr_v4),
- &(api_nh->gate.ipv4),
- sizeof(struct in_addr));
- zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api.prefix);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6,
- api_nh->vrf_id);
- break;
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- memset(&vtep_ip, 0, sizeof(struct ipaddr));
- ifindex = api_nh->ifindex;
- nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
- ifindex,
- api_nh->vrf_id);
-
- /* Special handling for IPv6 routes sourced from EVPN:
- * the nexthop and associated MAC need to be installed.
- */
- if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
- vtep_ip.ipa_type = IPADDR_V6;
- memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
- sizeof(struct in6_addr));
- zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api.prefix);
+ if (nexthop->nh_label &&
+ nexthop->nh_label->num_labels > 0) {
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label,
+ labelbuf, sizeof(labelbuf),
+ false);
}
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- nexthop = nexthop_from_blackhole(api_nh->bh_type);
- break;
+
+ zlog_debug("%s: nh=%s, vrf_id=%d %s",
+ __func__, nhbuf, api_nh->vrf_id, labelbuf);
}
+ /* Add new nexthop to temporary list. This list is
+ * canonicalized - sorted - so that it can be hashed later
+ * in route processing. We expect that the sender has sent
+ * the list sorted, and the zapi client api attempts to enforce
+ * that, so this should be inexpensive - but it is necessary
+ * to support shared nexthop-groups.
+ */
+ nexthop_group_add_sorted(ng, nexthop);
+ }
+
+ /* Allocate temporary list of backup nexthops, if necessary */
+ if (api.backup_nexthop_num > 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: adding %d backup nexthops",
+ __func__, api.backup_nexthop_num);
+
+ bnhg = zebra_nhg_backup_alloc();
+ nexthop = NULL;
+ last_nh = NULL;
+ }
+
+ /* Copy backup nexthops also, if present */
+ for (i = 0; i < api.backup_nexthop_num; i++) {
+ api_nh = &api.backup_nexthops[i];
+
+ /* Convert zapi backup nexthop */
+ nexthop = nexthop_from_zapi(re, api_nh, &api);
if (!nexthop) {
flog_warn(
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
- "%s: Nexthops Specified: %d but we failed to properly create one",
- __func__, api.nexthop_num);
+ "%s: Backup Nexthops Specified: %d but we failed to properly create one",
+ __func__, api.backup_nexthop_num);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
-
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
- nexthop->weight = api_nh->weight;
+ /* Backup nexthops can't have backups; that's not valid. */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (IS_ZEBRA_DEBUG_RECV) {
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+ zlog_debug("%s: backup nh %s with BACKUP flag!",
+ __func__, nhbuf);
+ }
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nexthop->backup_idx = 0;
+ }
/* MPLS labels for BGP-LU or Segment Routing */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
- && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) {
- enum lsp_types_t label_type;
+ && api_nh->type != NEXTHOP_TYPE_BLACKHOLE
+ && api_nh->label_num > 0) {
label_type = lsp_type_from_re_type(client->proto);
-
- if (IS_ZEBRA_DEBUG_RECV) {
- zlog_debug(
- "%s: adding %d labels of type %d (1st=%u)",
- __func__, api_nh->label_num, label_type,
- api_nh->labels[0]);
- }
-
nexthop_add_labels(nexthop, label_type,
api_nh->label_num,
&api_nh->labels[0]);
}
- /* Add new nexthop to temporary list */
- nexthop_group_add_sorted(ng, nexthop);
+ if (IS_ZEBRA_DEBUG_RECV) {
+ labelbuf[0] = '\0';
+ nhbuf[0] = '\0';
+
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+
+ if (nexthop->nh_label &&
+ nexthop->nh_label->num_labels > 0) {
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label,
+ labelbuf, sizeof(labelbuf),
+ false);
+ }
+
+ zlog_debug("%s: backup nh=%s, vrf_id=%d %s",
+ __func__, nhbuf, api_nh->vrf_id, labelbuf);
+ }
+
+ /* Note that the order of the backup nexthops is significant,
+ * so we don't sort this list as we do the primary nexthops,
+ * we just append.
+ */
+ if (last_nh)
+ NEXTHOP_APPEND(last_nh, nexthop);
+ else
+ bnhg->nhe->nhg.nexthop = nexthop;
+
+ last_nh = nexthop;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
@@ -1620,6 +1765,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
"%s: Received SRC Prefix but afi is not v6",
__func__);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
@@ -1631,10 +1777,28 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
"%s: Received safi: %d but we can only accept UNICAST or MULTICAST",
__func__, api.safi);
nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
XFREE(MTYPE_RE, re);
return;
}
- ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng);
+
+ /* Include backup info with the route. We use a temporary nhe here;
+ * if this is a new/unknown nhe, a new copy will be allocated
+ * and stored.
+ */
+ zebra_nhe_init(&nhe, afi, ng->nexthop);
+ nhe.nhg.nexthop = ng->nexthop;
+ nhe.backup_info = bnhg;
+ ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p,
+ re, &nhe);
+
+ /* At this point, these allocations are not needed: 're' has been
+ * retained or freed, and if 're' still exists, it is using
+ * a reference to a shared group object.
+ */
+ nexthop_group_delete(&ng);
+ if (bnhg)
+ zebra_nhg_backup_free(&bnhg);
/* Stats */
switch (api.prefix.family) {
@@ -1766,9 +1930,11 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
unsigned short instance;
uint8_t notify;
uint8_t synchronous;
+ uint32_t session_id;
STREAM_GETC(msg, proto);
STREAM_GETW(msg, instance);
+ STREAM_GETL(msg, session_id);
STREAM_GETC(msg, notify);
STREAM_GETC(msg, synchronous);
if (notify)
@@ -1788,6 +1954,7 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
client->proto = proto;
client->instance = instance;
+ client->session_id = session_id;
/* Graceful restart processing for client connect */
zebra_gr_client_reconnect(client);
@@ -2031,7 +2198,7 @@ static void zread_label_manager_connect(struct zserv *client,
client->instance = instance;
/* call hook for connection using wrapper */
- lm_client_connect_call(proto, instance, vrf_id);
+ lm_client_connect_call(client, vrf_id);
stream_failure:
return;
@@ -2057,19 +2224,10 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
STREAM_GETL(s, size);
STREAM_GETL(s, base);
- /* call hook to get a chunk using wrapper */
- lm_get_chunk_call(&lmc, proto, instance, keep, size, base, vrf_id);
+ assert(proto == client->proto && instance == client->instance);
- if (!lmc)
- flog_err(
- EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,
- "Unable to assign Label Chunk of size %u to %s instance %u",
- size, zebra_route_string(proto), instance);
- else
- if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
- lmc->start, lmc->end,
- zebra_route_string(proto), instance);
+ /* call hook to get a chunk using wrapper */
+ lm_get_chunk_call(&lmc, client, keep, size, base, vrf_id);
stream_failure:
return;
@@ -2091,8 +2249,10 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)
STREAM_GETL(s, start);
STREAM_GETL(s, end);
+ assert(proto == client->proto && instance == client->instance);
+
/* call hook to release a chunk using wrapper */
- lm_release_chunk_call(proto, instance, start, end);
+ lm_release_chunk_call(client, start, end);
stream_failure:
return;
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 996a255ff4..a4f5e74e4d 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -94,8 +94,7 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
extern void zsend_capabilities_all_clients(void);
extern int zsend_assign_label_chunk_response(struct zserv *client,
- vrf_id_t vrf_id, uint8_t proto,
- uint16_t instance,
+ vrf_id_t vrf_id,
struct label_manager_chunk *lmc);
extern int zsend_label_manager_connect_response(struct zserv *client,
vrf_id_t vrf_id,
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 459d2bc620..143354b166 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -32,6 +32,7 @@
#include "zebra/zebra_memory.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/rt.h"
#include "zebra/debug.h"
@@ -113,10 +114,15 @@ struct dplane_route_info {
struct dplane_nexthop_info nhe;
/* Nexthops */
+ uint32_t zd_nhg_id;
struct nexthop_group zd_ng;
+ /* Backup nexthops (if present) */
+ struct nexthop_group backup_ng;
+
/* "Previous" nexthops, used only in route updates without netlink */
struct nexthop_group zd_old_ng;
+ struct nexthop_group old_backup_ng;
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
@@ -173,7 +179,6 @@ struct dplane_mac_info {
struct ethaddr mac;
struct in_addr vtep_ip;
bool is_sticky;
-
};
/*
@@ -396,7 +401,7 @@ static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
static enum zebra_dplane_result intf_addr_update_internal(
const struct interface *ifp, const struct connected *ifc,
enum dplane_op_e op);
-static enum zebra_dplane_result mac_update_internal(
+static enum zebra_dplane_result mac_update_common(
enum dplane_op_e op, const struct interface *ifp,
const struct interface *br_ifp,
vlanid_t vid, const struct ethaddr *mac,
@@ -440,23 +445,15 @@ void dplane_enable_sys_route_notifs(void)
}
/*
- * Free a dataplane results context.
+ * Clean up dependent/internal allocations inside a context object
*/
-static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
+static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
{
- if (pctx == NULL)
- return;
-
- DPLANE_CTX_VALID(*pctx);
-
- /* TODO -- just freeing memory, but would like to maintain
- * a pool
- */
-
- /* Some internal allocations may need to be freed, depending on
+ /*
+ * Some internal allocations may need to be freed, depending on
* the type of info captured in the ctx.
*/
- switch ((*pctx)->zd_op) {
+ switch (ctx->zd_op) {
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
@@ -465,18 +462,33 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_ROUTE_NOTIFY:
/* Free allocated nexthops */
- if ((*pctx)->u.rinfo.zd_ng.nexthop) {
+ if (ctx->u.rinfo.zd_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.zd_ng.nexthop);
+ nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
- (*pctx)->u.rinfo.zd_ng.nexthop = NULL;
+ ctx->u.rinfo.zd_ng.nexthop = NULL;
}
- if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
+ /* Free backup info also (if present) */
+ if (ctx->u.rinfo.backup_ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
+ nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
- (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
+ ctx->u.rinfo.backup_ng.nexthop = NULL;
+ }
+
+ if (ctx->u.rinfo.zd_old_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free(ctx->u.rinfo.zd_old_ng.nexthop);
+
+ ctx->u.rinfo.zd_old_ng.nexthop = NULL;
+ }
+
+ if (ctx->u.rinfo.old_backup_ng.nexthop) {
+ /* This deals with recursive nexthops too */
+ nexthops_free(ctx->u.rinfo.old_backup_ng.nexthop);
+
+ ctx->u.rinfo.old_backup_ng.nexthop = NULL;
}
break;
@@ -484,11 +496,11 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_NH_INSTALL:
case DPLANE_OP_NH_UPDATE:
case DPLANE_OP_NH_DELETE: {
- if ((*pctx)->u.rinfo.nhe.ng.nexthop) {
+ if (ctx->u.rinfo.nhe.ng.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.rinfo.nhe.ng.nexthop);
+ nexthops_free(ctx->u.rinfo.nhe.ng.nexthop);
- (*pctx)->u.rinfo.nhe.ng.nexthop = NULL;
+ ctx->u.rinfo.nhe.ng.nexthop = NULL;
}
break;
}
@@ -501,7 +513,7 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
zebra_nhlfe_t *nhlfe, *next;
/* Free allocated NHLFEs */
- for (nhlfe = (*pctx)->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
+ for (nhlfe = ctx->u.lsp.nhlfe_list; nhlfe; nhlfe = next) {
next = nhlfe->next;
zebra_mpls_nhlfe_del(nhlfe);
@@ -510,8 +522,8 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
/* Clear pointers in lsp struct, in case we're cacheing
* free context structs.
*/
- (*pctx)->u.lsp.nhlfe_list = NULL;
- (*pctx)->u.lsp.best_nhlfe = NULL;
+ ctx->u.lsp.nhlfe_list = NULL;
+ ctx->u.lsp.best_nhlfe = NULL;
break;
}
@@ -519,21 +531,21 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_PW_INSTALL:
case DPLANE_OP_PW_UNINSTALL:
/* Free allocated nexthops */
- if ((*pctx)->u.pw.nhg.nexthop) {
+ if (ctx->u.pw.nhg.nexthop) {
/* This deals with recursive nexthops too */
- nexthops_free((*pctx)->u.pw.nhg.nexthop);
+ nexthops_free(ctx->u.pw.nhg.nexthop);
- (*pctx)->u.pw.nhg.nexthop = NULL;
+ ctx->u.pw.nhg.nexthop = NULL;
}
break;
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
/* Maybe free label string, if allocated */
- if ((*pctx)->u.intf.label != NULL &&
- (*pctx)->u.intf.label != (*pctx)->u.intf.label_buf) {
- free((*pctx)->u.intf.label);
- (*pctx)->u.intf.label = NULL;
+ if (ctx->u.intf.label != NULL &&
+ ctx->u.intf.label != ctx->u.intf.label_buf) {
+ free(ctx->u.intf.label);
+ ctx->u.intf.label = NULL;
}
break;
@@ -547,11 +559,41 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
case DPLANE_OP_NONE:
break;
}
+}
+
+/*
+ * Free a dataplane results context.
+ */
+static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
+{
+ if (pctx == NULL)
+ return;
+
+ DPLANE_CTX_VALID(*pctx);
+
+ /* TODO -- just freeing memory, but would like to maintain
+ * a pool
+ */
+
+ /* Some internal allocations may need to be freed, depending on
+ * the type of info captured in the ctx.
+ */
+ dplane_ctx_free_internal(*pctx);
XFREE(MTYPE_DP_CTX, *pctx);
}
/*
+ * Reset an allocated context object for re-use. All internal allocations are
+ * freed and the context is memset.
+ */
+void dplane_ctx_reset(struct zebra_dplane_ctx *ctx)
+{
+ dplane_ctx_free_internal(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+/*
* Return a context block to the dplane module after processing
*/
void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
@@ -1038,6 +1080,12 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
}
+uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.zd_nhg_id;
+}
+
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx)
{
@@ -1046,14 +1094,30 @@ const struct nexthop_group *dplane_ctx_get_ng(
return &(ctx->u.rinfo.zd_ng);
}
-const struct nexthop_group *dplane_ctx_get_old_ng(
- const struct zebra_dplane_ctx *ctx)
+const struct nexthop_group *
+dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.backup_ng);
+}
+
+const struct nexthop_group *
+dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->u.rinfo.zd_old_ng);
}
+const struct nexthop_group *
+dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rinfo.old_backup_ng);
+}
+
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx)
{
@@ -1461,10 +1525,8 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
/*
* Initialize a context block for a route update from zebra data structs.
*/
-static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
- enum dplane_op_e op,
- struct route_node *rn,
- struct route_entry *re)
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re)
{
int ret = EINVAL;
const struct route_table *table = NULL;
@@ -1473,6 +1535,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
struct zebra_ns *zns;
struct zebra_vrf *zvrf;
struct nexthop *nexthop;
+ zebra_l3vni_t *zl3vni;
if (!ctx || !rn || !re)
goto done;
@@ -1514,11 +1577,32 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
/* Copy nexthops; recursive info is included too */
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
re->nhe->nhg.nexthop, NULL);
+ ctx->u.rinfo.zd_nhg_id = re->nhe->id;
- /* Ensure that the dplane nexthops' flags are clear. */
- for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
+ /* Copy backup nexthop info, if present */
+ if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
+ copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
+ re->nhe->backup_info->nhe->nhg.nexthop, NULL);
+ }
+
+ /*
+ * Ensure that the dplane nexthops' flags are clear and copy
+ * encapsulation information.
+ */
+ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+ /* Check for available encapsulations. */
+ if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
+ continue;
+
+ zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
+ if (zl3vni && is_l3vni_oper_up(zl3vni)) {
+ nexthop->nh_encap_type = NET_VXLAN;
+ nexthop->nh_encap.vni = zl3vni->vni;
+ }
+ }
+
/* Don't need some info when capturing a system notification */
if (op == DPLANE_OP_SYS_ROUTE_ADD ||
op == DPLANE_OP_SYS_ROUTE_DELETE) {
@@ -1532,9 +1616,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
#ifdef HAVE_NETLINK
- if (re->nhe_id) {
- struct nhg_hash_entry *nhe =
- zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id));
+ {
+ struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
ctx->u.rinfo.nhe.id = nhe->id;
/*
@@ -1581,7 +1664,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
{
struct zebra_vrf *zvrf = NULL;
struct zebra_ns *zns = NULL;
-
int ret = EINVAL;
if (!ctx || !nhe)
@@ -1850,6 +1932,17 @@ dplane_route_update_internal(struct route_node *rn,
*/
copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
old_re->nhe->nhg.nexthop, NULL);
+
+ if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
+ struct nexthop_group *nhg;
+ struct nexthop **nh;
+
+ nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
+ nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
+
+ if (nhg->nexthop)
+ copy_nexthops(nh, nhg->nexthop, NULL);
+ }
#endif /* !HAVE_NETLINK */
}
@@ -2412,8 +2505,8 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp,
enum zebra_dplane_result result;
/* Use common helper api */
- result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
+ vid, mac, vtep_ip, sticky);
return result;
}
@@ -2429,41 +2522,25 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp,
enum zebra_dplane_result result;
/* Use common helper api */
- result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
- vid, mac, vtep_ip, false);
+ result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
+ vid, mac, vtep_ip, false);
return result;
}
/*
- * Common helper api for MAC address/vxlan updates
+ * Public api to init an empty context - either newly-allocated or
+ * reset/cleared - for a MAC update.
*/
-static enum zebra_dplane_result
-mac_update_internal(enum dplane_op_e op,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky)
+void dplane_mac_init(struct zebra_dplane_ctx *ctx,
+ const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ struct in_addr vtep_ip,
+ bool sticky)
{
- enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
- int ret;
- struct zebra_dplane_ctx *ctx = NULL;
struct zebra_ns *zns;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
- char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
-
- zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
- dplane_op2str(op),
- prefix_mac2str(mac, buf1, sizeof(buf1)),
- ifp->name,
- inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
- }
-
- ctx = dplane_ctx_alloc();
-
- ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
ctx->zd_vrf_id = ifp->vrf_id;
@@ -2481,6 +2558,39 @@ mac_update_internal(enum dplane_op_e op,
ctx->u.macinfo.mac = *mac;
ctx->u.macinfo.vid = vid;
ctx->u.macinfo.is_sticky = sticky;
+}
+
+/*
+ * Common helper api for MAC address/vxlan updates
+ */
+static enum zebra_dplane_result
+mac_update_common(enum dplane_op_e op,
+ const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ struct in_addr vtep_ip,
+ bool sticky)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
+
+ zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s",
+ dplane_op2str(op),
+ prefix_mac2str(mac, buf1, sizeof(buf1)),
+ ifp->name,
+ inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2)));
+ }
+
+ ctx = dplane_ctx_alloc();
+ ctx->zd_op = op;
+
+ /* Common init for the ctx */
+ dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky);
/* Enqueue for processing on the dplane pthread */
ret = dplane_update_enqueue(ctx);
@@ -3447,12 +3557,20 @@ bool dplane_is_in_shutdown(void)
*/
void zebra_dplane_pre_finish(void)
{
+ struct zebra_dplane_provider *dp;
+
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane pre-fini called");
zdplane_info.dg_is_shutdown = true;
- /* TODO -- Notify provider(s) of pending shutdown */
+ /* Notify provider(s) of pending shutdown. */
+ TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
+ if (dp->dp_fini == NULL)
+ continue;
+
+ dp->dp_fini(dp, true);
+ }
}
/*
@@ -3753,6 +3871,8 @@ done:
*/
void zebra_dplane_shutdown(void)
{
+ struct zebra_dplane_provider *dp;
+
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane shutdown called");
@@ -3771,7 +3891,13 @@ void zebra_dplane_shutdown(void)
zdplane_info.dg_pthread = NULL;
zdplane_info.dg_master = NULL;
- /* TODO -- Notify provider(s) of final shutdown */
+ /* Notify provider(s) of final shutdown. */
+ TAILQ_FOREACH(dp, &zdplane_info.dg_providers_q, dp_prov_link) {
+ if (dp->dp_fini == NULL)
+ continue;
+
+ dp->dp_fini(dp, false);
+ }
/* TODO -- Clean-up provider objects */
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index c0b04e71b0..f01ca2e84c 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -180,6 +180,12 @@ TAILQ_HEAD(dplane_ctx_q, zebra_dplane_ctx);
/* Allocate a context object */
struct zebra_dplane_ctx *dplane_ctx_alloc(void);
+/*
+ * Reset an allocated context object for re-use. All internal allocations are
+ * freed.
+ */
+void dplane_ctx_reset(struct zebra_dplane_ctx *ctx);
+
/* Return a dataplane results context block after use; the caller's pointer will
* be cleared.
*/
@@ -270,11 +276,19 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
+
+uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_old_ng(
const struct zebra_dplane_ctx *ctx);
+/* Backup nexthop information (list of nexthops) if present. */
+const struct nexthop_group *
+dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx);
+const struct nexthop_group *
+dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx);
+
/* Accessors for nexthop information */
uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx);
afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx);
@@ -430,6 +444,12 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
/*
* Enqueue evpn mac operations for the dataplane.
*/
+extern struct zebra_dplane_ctx *mac_update_internal(
+ enum dplane_op_e op, const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid, const struct ethaddr *mac,
+ struct in_addr vtep_ip, bool sticky);
+
enum zebra_dplane_result dplane_mac_add(const struct interface *ifp,
const struct interface *bridge_ifp,
vlanid_t vid,
@@ -443,6 +463,15 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp,
const struct ethaddr *mac,
struct in_addr vtep_ip);
+/* Helper api to init an empty or new context for a MAC update */
+void dplane_mac_init(struct zebra_dplane_ctx *ctx,
+ const struct interface *ifp,
+ const struct interface *br_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ struct in_addr vtep_ip,
+ bool sticky);
+
/*
* Enqueue evpn neighbor updates for the dataplane.
*/
@@ -466,6 +495,9 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
const struct in_addr *ip,
vni_t vni);
+/* Encode route information into data plane context. */
+int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct route_node *rn, struct route_entry *re);
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 0190ee2b8d..41d73f3c97 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -1470,8 +1470,6 @@ static int zfpm_trigger_update(struct route_node *rn, const char *reason)
/*
* Generate Key for FPM MAC info hash entry
- * Key is generated using MAC address and VNI id which should be sufficient
- * to provide uniqueness
*/
static unsigned int zfpm_mac_info_hash_keymake(const void *p)
{
@@ -1494,8 +1492,6 @@ static bool zfpm_mac_info_cmp(const void *p1, const void *p2)
if (memcmp(fpm_mac1->macaddr.octet, fpm_mac2->macaddr.octet, ETH_ALEN)
!= 0)
return false;
- if (fpm_mac1->r_vtep_ip.s_addr != fpm_mac2->r_vtep_ip.s_addr)
- return false;
if (fpm_mac1->vni != fpm_mac2->vni)
return false;
@@ -1521,7 +1517,6 @@ static void *zfpm_mac_info_alloc(void *p)
fpm_mac = XCALLOC(MTYPE_FPM_MAC_INFO, sizeof(struct fpm_mac_info_t));
memcpy(&fpm_mac->macaddr, &key->macaddr, ETH_ALEN);
- memcpy(&fpm_mac->r_vtep_ip, &key->r_vtep_ip, sizeof(struct in_addr));
fpm_mac->vni = key->vni;
return (void *)fpm_mac;
@@ -1552,6 +1547,7 @@ static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
char buf[ETHER_ADDR_STRLEN];
struct fpm_mac_info_t *fpm_mac, key;
struct interface *vxlan_if, *svi_if;
+ bool mac_found = false;
/*
* Ignore if the connection is down. We will update the FPM about
@@ -1572,56 +1568,34 @@ static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
memset(&key, 0, sizeof(struct fpm_mac_info_t));
memcpy(&key.macaddr, &rmac->macaddr, ETH_ALEN);
- key.r_vtep_ip.s_addr = rmac->fwd_info.r_vtep_ip.s_addr;
key.vni = zl3vni->vni;
/* Check if this MAC is already present in the queue. */
fpm_mac = zfpm_mac_info_lookup(&key);
if (fpm_mac) {
- if (!!CHECK_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM)
- == delete) {
- /*
- * MAC is already present in the queue
- * with the same op as this one. Do nothing
- */
- zfpm_g->stats.redundant_triggers++;
- return 0;
- }
+ mac_found = true;
/*
- * A new op for an already existing fpm_mac_info_t node.
- * Update the existing node for the new op.
+ * If the enqueued op is "add" and current op is "delete",
+ * this is a noop. So, Unset ZEBRA_MAC_UPDATE_FPM flag.
+ * While processing FPM queue, we will silently delete this
+ * MAC entry without sending any update for this MAC.
*/
- if (!delete) {
- /*
- * New op is "add". Previous op is "delete".
- * Update the fpm_mac_info_t for the new add.
- */
- fpm_mac->zebra_flags = rmac->flags;
-
- fpm_mac->vxlan_if = vxlan_if ? vxlan_if->ifindex : 0;
- fpm_mac->svi_if = svi_if ? svi_if->ifindex : 0;
-
- UNSET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM);
- SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM);
- } else {
- /*
- * New op is "delete". Previous op is "add".
- * Thus, no-op. Unset ZEBRA_MAC_UPDATE_FPM flag.
- */
+ if (!CHECK_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM) &&
+ delete == 1) {
SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM);
UNSET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM);
+ return 0;
}
-
- return 0;
+ } else {
+ fpm_mac = hash_get(zfpm_g->fpm_mac_info_table, &key,
+ zfpm_mac_info_alloc);
+ if (!fpm_mac)
+ return 0;
}
- fpm_mac = hash_get(zfpm_g->fpm_mac_info_table, &key,
- zfpm_mac_info_alloc);
- if (!fpm_mac)
- return 0;
-
+ fpm_mac->r_vtep_ip.s_addr = rmac->fwd_info.r_vtep_ip.s_addr;
fpm_mac->zebra_flags = rmac->flags;
fpm_mac->vxlan_if = vxlan_if ? vxlan_if->ifindex : 0;
fpm_mac->svi_if = svi_if ? svi_if->ifindex : 0;
@@ -1629,8 +1603,11 @@ static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM);
if (delete)
SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM);
+ else
+ UNSET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM);
- TAILQ_INSERT_TAIL(&zfpm_g->mac_q, fpm_mac, fpm_mac_q_entries);
+ if (!mac_found)
+ TAILQ_INSERT_TAIL(&zfpm_g->mac_q, fpm_mac, fpm_mac_q_entries);
zfpm_g->stats.updates_triggered++;
@@ -1961,8 +1938,15 @@ static int fpm_remote_srv_write(struct vty *vty)
}
+static int fpm_remote_srv_write(struct vty *vty);
/* Zebra node */
-static struct cmd_node zebra_node = {ZEBRA_NODE, "", 1};
+static struct cmd_node zebra_node = {
+ .name = "zebra",
+ .node = ZEBRA_NODE,
+ .parent_node = CONFIG_NODE,
+ .prompt = "",
+ .config_write = fpm_remote_srv_write,
+};
/**
@@ -1999,7 +1983,7 @@ static int zfpm_init(struct thread_master *master)
zfpm_stats_init(&zfpm_g->last_ivl_stats);
zfpm_stats_init(&zfpm_g->cumulative_stats);
- install_node(&zebra_node, fpm_remote_srv_write);
+ install_node(&zebra_node);
install_element(ENABLE_NODE, &show_zebra_fpm_stats_cmd);
install_element(ENABLE_NODE, &clear_zebra_fpm_stats_cmd);
install_element(CONFIG_NODE, &fpm_remote_ip_cmd);
diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c
index ade4b636d6..4b31cc0281 100644
--- a/zebra/zebra_fpm_protobuf.c
+++ b/zebra/zebra_fpm_protobuf.c
@@ -294,7 +294,7 @@ int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re,
return 0;
}
- len = fpm__message__pack(msg, (uint8_t *)in_buf);
+ len = fpm__message__pack(msg, in_buf);
assert(len <= in_buf_len);
QPB_RESET_STACK_ALLOCATOR(allocator);
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index d373fdf370..999e91486d 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -98,14 +98,14 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp);
static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size);
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex);
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex, uint8_t num_labels,
- mpls_label_t *labels);
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex,
+ uint8_t num_labels, mpls_label_t *labels);
static int nhlfe_del(zebra_nhlfe_t *snhlfe);
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
struct mpls_label_stack *nh_label);
@@ -117,13 +117,13 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
static void lsp_print(zebra_lsp_t *lsp, void *ctxt);
static void *slsp_alloc(void *p);
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex,
+ const union g_addr *gate, ifindex_t ifindex,
mpls_label_t out_label);
static int snhlfe_del(zebra_snhlfe_t *snhlfe);
static int snhlfe_del_all(zebra_slsp_t *slsp);
@@ -960,7 +960,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
/* We leave the INSTALLED flag set here
- * so we know an update in in-flight.
+ * so we know an update is in-flight.
*/
/*
@@ -1149,7 +1149,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
* Check if NHLFE matches with search info passed.
*/
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct nexthop *nhop;
int cmp = 1;
@@ -1191,8 +1191,8 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
* Locate NHLFE that matches with passed info.
*/
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex)
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex)
{
zebra_nhlfe_t *nhlfe;
@@ -1214,9 +1214,9 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
* check done.
*/
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
- enum nexthop_types_t gtype, union g_addr *gate,
- ifindex_t ifindex, uint8_t num_labels,
- mpls_label_t labels[])
+ enum nexthop_types_t gtype,
+ const union g_addr *gate, ifindex_t ifindex,
+ uint8_t num_labels, mpls_label_t labels[])
{
zebra_nhlfe_t *nhlfe;
struct nexthop *nexthop;
@@ -1520,7 +1520,7 @@ static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
/*
* Compare two LSPs based on their label values.
*/
-static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
+static int lsp_cmp(const zebra_lsp_t *lsp1, const zebra_lsp_t *lsp2)
{
if (lsp1->ile.in_label < lsp2->ile.in_label)
return -1;
@@ -1547,7 +1547,7 @@ static void *slsp_alloc(void *p)
/*
* Compare two static LSPs based on their label values.
*/
-static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
+static int slsp_cmp(const zebra_slsp_t *slsp1, const zebra_slsp_t *slsp2)
{
if (slsp1->ile.in_label < slsp2->ile.in_label)
return -1;
@@ -1562,7 +1562,7 @@ static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
* Check if static NHLFE matches with search info passed.
*/
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
int cmp = 1;
@@ -1593,7 +1593,7 @@ static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
*/
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
zebra_snhlfe_t *snhlfe;
@@ -1615,7 +1615,7 @@ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
*/
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex,
+ const union g_addr *gate, ifindex_t ifindex,
mpls_label_t out_label)
{
zebra_snhlfe_t *snhlfe;
@@ -2746,7 +2746,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, uint8_t num_out_labels,
mpls_label_t out_labels[], enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -2759,11 +2759,12 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
if (!lsp_table)
return -1;
- /* If entry is present, exit. */
+ /* Find or create LSP object */
tmp_ile.in_label = in_label;
lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
if (!lsp)
return -1;
+
nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
if (nhlfe) {
struct nexthop *nh = nhlfe->nexthop;
@@ -2780,8 +2781,8 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
return 0;
if (IS_ZEBRA_DEBUG_MPLS) {
- char buf2[BUFSIZ];
- char buf3[BUFSIZ];
+ char buf2[MPLS_LABEL_STRLEN];
+ char buf3[MPLS_LABEL_STRLEN];
nhlfe2str(nhlfe, buf, BUFSIZ);
mpls_label2str(num_out_labels, out_labels, buf2,
@@ -2842,7 +2843,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex)
+ const union g_addr *gate, ifindex_t ifindex)
{
struct hash *lsp_table;
zebra_ile_t tmp_ile;
@@ -3056,11 +3057,12 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
if (!slsp_table)
return -1;
- /* If entry is present, exit. */
+ /* Find or create LSP. */
tmp_ile.in_label = in_label;
slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
if (!slsp)
return -1;
+
snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
if (snhlfe) {
if (snhlfe->out_label == out_label)
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 2489e8e510..33cb614346 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -288,7 +288,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, uint8_t num_out_labels,
mpls_label_t out_labels[], enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall a particular NHLFE in the forwarding table. If this is
@@ -296,7 +296,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
*/
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
mpls_label_t in_label, enum nexthop_types_t gtype,
- union g_addr *gate, ifindex_t ifindex);
+ const union g_addr *gate, ifindex_t ifindex);
/*
* Uninstall all NHLFEs for a particular LSP forwarding entry.
diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c
index 796aa3f666..d789f20071 100644
--- a/zebra/zebra_mpls_vty.c
+++ b/zebra/zebra_mpls_vty.c
@@ -449,15 +449,21 @@ DEFUN (no_mpls_label_global_block,
return zebra_mpls_global_block(vty, 0, NULL, NULL);
}
+static int zebra_mpls_config(struct vty *vty);
/* MPLS node for MPLS LSP. */
-static struct cmd_node mpls_node = {MPLS_NODE, "", 1};
+static struct cmd_node mpls_node = {
+ .name = "mpls",
+ .node = MPLS_NODE,
+ .prompt = "",
+ .config_write = zebra_mpls_config,
+};
/* MPLS VTY. */
void zebra_mpls_vty_init(void)
{
install_element(VIEW_NODE, &show_mpls_status_cmd);
- install_node(&mpls_node, zebra_mpls_config);
+ install_node(&mpls_node);
install_element(CONFIG_NODE, &mpls_transit_lsp_cmd);
install_element(CONFIG_NODE, &no_mpls_transit_lsp_cmd);
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
new file mode 100644
index 0000000000..1f3468d6dc
--- /dev/null
+++ b/zebra/zebra_nb.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 2020 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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
+ */
+
+#include <zebra.h>
+#include "northbound.h"
+#include "libfrr.h"
+#include "zebra_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_zebra_info = {
+ .name = "frr-zebra",
+ .nodes = {
+ {
+ .xpath = "/frr-zebra:zebra/mcast-rpf-lookup",
+ .cbs = {
+ .modify = zebra_mcast_rpf_lookup_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/ip-forwarding",
+ .cbs = {
+ .modify = zebra_ip_forwarding_modify,
+ .destroy = zebra_ip_forwarding_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/ipv6-forwarding",
+ .cbs = {
+ .modify = zebra_ipv6_forwarding_modify,
+ .destroy = zebra_ipv6_forwarding_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/workqueue-hold-timer",
+ .cbs = {
+ .modify = zebra_workqueue_hold_timer_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/zapi-packets",
+ .cbs = {
+ .modify = zebra_zapi_packets_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/table-id",
+ .cbs = {
+ .modify = zebra_import_kernel_table_table_id_modify,
+ .destroy = zebra_import_kernel_table_table_id_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/distance",
+ .cbs = {
+ .modify = zebra_import_kernel_table_distance_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/import-kernel-table/route-map",
+ .cbs = {
+ .modify = zebra_import_kernel_table_route_map_modify,
+ .destroy = zebra_import_kernel_table_route_map_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/allow-external-route-update",
+ .cbs = {
+ .create = zebra_allow_external_route_update_create,
+ .destroy = zebra_allow_external_route_update_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/dplane-queue-limit",
+ .cbs = {
+ .modify = zebra_dplane_queue_limit_modify,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping",
+ .cbs = {
+ .create = zebra_vrf_vni_mapping_create,
+ .destroy = zebra_vrf_vni_mapping_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping/vni-id",
+ .cbs = {
+ .modify = zebra_vrf_vni_mapping_vni_id_modify,
+ .destroy = zebra_vrf_vni_mapping_vni_id_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/vrf-vni-mapping/prefix-only",
+ .cbs = {
+ .create = zebra_vrf_vni_mapping_prefix_only_create,
+ .destroy = zebra_vrf_vni_mapping_prefix_only_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-events",
+ .cbs = {
+ .modify = zebra_debugs_debug_events_modify,
+ .destroy = zebra_debugs_debug_events_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-send",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_send_modify,
+ .destroy = zebra_debugs_debug_zapi_send_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-recv",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_recv_modify,
+ .destroy = zebra_debugs_debug_zapi_recv_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-zapi-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_zapi_detail_modify,
+ .destroy = zebra_debugs_debug_zapi_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_modify,
+ .destroy = zebra_debugs_debug_kernel_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-send",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_msg_send_modify,
+ .destroy = zebra_debugs_debug_kernel_msg_send_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-recv",
+ .cbs = {
+ .modify = zebra_debugs_debug_kernel_msg_recv_modify,
+ .destroy = zebra_debugs_debug_kernel_msg_recv_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-rib",
+ .cbs = {
+ .modify = zebra_debugs_debug_rib_modify,
+ .destroy = zebra_debugs_debug_rib_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-rib-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_rib_detail_modify,
+ .destroy = zebra_debugs_debug_rib_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-fpm",
+ .cbs = {
+ .modify = zebra_debugs_debug_fpm_modify,
+ .destroy = zebra_debugs_debug_fpm_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-nht",
+ .cbs = {
+ .modify = zebra_debugs_debug_nht_modify,
+ .destroy = zebra_debugs_debug_nht_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-nht-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_nht_detail_modify,
+ .destroy = zebra_debugs_debug_nht_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-mpls",
+ .cbs = {
+ .modify = zebra_debugs_debug_mpls_modify,
+ .destroy = zebra_debugs_debug_mpls_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-vxlan",
+ .cbs = {
+ .modify = zebra_debugs_debug_vxlan_modify,
+ .destroy = zebra_debugs_debug_vxlan_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-pw",
+ .cbs = {
+ .modify = zebra_debugs_debug_pw_modify,
+ .destroy = zebra_debugs_debug_pw_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-dplane",
+ .cbs = {
+ .modify = zebra_debugs_debug_dplane_modify,
+ .destroy = zebra_debugs_debug_dplane_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-dplane-detail",
+ .cbs = {
+ .modify = zebra_debugs_debug_dplane_detail_modify,
+ .destroy = zebra_debugs_debug_dplane_detail_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:zebra/debugs/debug-mlag",
+ .cbs = {
+ .modify = zebra_debugs_debug_mlag_modify,
+ .destroy = zebra_debugs_debug_mlag_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-route-information",
+ .cbs = {
+ .rpc = get_route_information_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-v6-mroute-info",
+ .cbs = {
+ .rpc = get_v6_mroute_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vrf-info",
+ .cbs = {
+ .rpc = get_vrf_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vrf-vni-info",
+ .cbs = {
+ .rpc = get_vrf_vni_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-info",
+ .cbs = {
+ .rpc = get_evpn_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-vni-info",
+ .cbs = {
+ .rpc = get_vni_info_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-vni-rmac",
+ .cbs = {
+ .rpc = get_evpn_vni_rmac_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-vni-nexthops",
+ .cbs = {
+ .rpc = get_evpn_vni_nexthops_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:clear-evpn-dup-addr",
+ .cbs = {
+ .rpc = clear_evpn_dup_addr_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-macs",
+ .cbs = {
+ .rpc = get_evpn_macs_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-evpn-arp-cache",
+ .cbs = {
+ .rpc = get_evpn_arp_cache_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-pbr-ipset",
+ .cbs = {
+ .rpc = get_pbr_ipset_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-pbr-iptable",
+ .cbs = {
+ .rpc = get_pbr_iptable_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-zebra:get-debugs",
+ .cbs = {
+ .rpc = get_debugs_rpc,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs",
+ .cbs = {
+ .create = lib_interface_zebra_ip_addrs_create,
+ .destroy = lib_interface_zebra_ip_addrs_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label",
+ .cbs = {
+ .modify = lib_interface_zebra_ip_addrs_label_modify,
+ .destroy = lib_interface_zebra_ip_addrs_label_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer",
+ .cbs = {
+ .modify = lib_interface_zebra_ip_addrs_ip4_peer_modify,
+ .destroy = lib_interface_zebra_ip_addrs_ip4_peer_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/multicast",
+ .cbs = {
+ .modify = lib_interface_zebra_multicast_modify,
+ .destroy = lib_interface_zebra_multicast_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect",
+ .cbs = {
+ .modify = lib_interface_zebra_link_detect_modify,
+ .destroy = lib_interface_zebra_link_detect_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/shutdown",
+ .cbs = {
+ .modify = lib_interface_zebra_shutdown_modify,
+ .destroy = lib_interface_zebra_shutdown_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth",
+ .cbs = {
+ .modify = lib_interface_zebra_bandwidth_modify,
+ .destroy = lib_interface_zebra_bandwidth_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/up-count",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_up_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/down-count",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_down_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/zif-type",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_zif_type_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/ptm-status",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_ptm_status_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/vlan-id",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_vlan_id_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/vni-id",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_vni_id_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/remote-vtep",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_remote_vtep_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/mcast-group",
+ .cbs = {
+ .get_elem = lib_interface_zebra_state_mcast_group_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib",
+ .cbs = {
+ .create = lib_vrf_ribs_rib_create,
+ .destroy = lib_vrf_ribs_rib_destroy,
+ .get_next = lib_vrf_ribs_rib_get_next,
+ .get_keys = lib_vrf_ribs_rib_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route",
+ .cbs = {
+ .get_next = lib_vrf_ribs_rib_route_get_next,
+ .get_keys = lib_vrf_ribs_rib_route_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_route_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/prefix",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_prefix_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry",
+ .cbs = {
+ .get_next = lib_vrf_ribs_rib_route_route_entry_get_next,
+ .get_keys = lib_vrf_ribs_rib_route_route_entry_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_route_route_entry_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/protocol",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_protocol_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/instance",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_instance_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/distance",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_distance_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/metric",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_metric_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/tag",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_tag_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/selected",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_selected_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/installed",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_installed_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/failed",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_failed_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/queued",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_queued_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-flags",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-status",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/uptime",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_uptime_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group",
+ .cbs = {
+ .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next,
+ .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/name",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop",
+ .cbs = {
+ .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next,
+ .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry",
+ .cbs = {
+ .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next,
+ .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys,
+ .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv4_prefix_length_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv4_prefix_length_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_ipv6_prefix_length_modify,
+ .destroy = lib_route_map_entry_match_condition_ipv6_prefix_length_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_source_protocol_modify,
+ .destroy = lib_route_map_entry_match_condition_source_protocol_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_source_instance_modify,
+ .destroy = lib_route_map_entry_match_condition_source_instance_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_source_v4_modify,
+ .destroy = lib_route_map_entry_set_action_source_v4_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_source_v6_modify,
+ .destroy = lib_route_map_entry_set_action_source_v6_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight",
+ .cbs = {
+ .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
new file mode 100644
index 0000000000..01a44e5525
--- /dev/null
+++ b/zebra/zebra_nb.h
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2020 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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
+ */
+
+#ifndef ZEBRA_ZEBRA_NB_H_
+#define ZEBRA_ZEBRA_NB_H_
+
+extern const struct frr_yang_module_info frr_zebra_info;
+
+/* prototypes */
+int get_route_information_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_v6_mroute_info_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_vrf_info_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_vrf_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_evpn_info_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_evpn_vni_rmac_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_evpn_vni_nexthops_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int clear_evpn_dup_addr_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_evpn_macs_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_evpn_arp_cache_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_pbr_ipset_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_pbr_iptable_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int get_debugs_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int zebra_mcast_rpf_lookup_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_ip_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_ip_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_ipv6_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_ipv6_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_workqueue_hold_timer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_zapi_packets_modify(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_import_kernel_table_table_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_import_kernel_table_table_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_import_kernel_table_distance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_import_kernel_table_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_import_kernel_table_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_allow_external_route_update_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_allow_external_route_update_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_dplane_queue_limit_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_vrf_vni_mapping_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_vrf_vni_mapping_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_vrf_vni_mapping_vni_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_vrf_vni_mapping_vni_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_vrf_vni_mapping_prefix_only_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_vrf_vni_mapping_prefix_only_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_events_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_events_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_zapi_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_zapi_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_zapi_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_zapi_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_zapi_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_zapi_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_kernel_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_kernel_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_kernel_msg_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_kernel_msg_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_kernel_msg_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_kernel_msg_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_rib_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_rib_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_rib_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_rib_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_fpm_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_fpm_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_nht_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_nht_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_nht_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_nht_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_mpls_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_mpls_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_vxlan_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_vxlan_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_pw_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_pw_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_dplane_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_dplane_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_dplane_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_dplane_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int zebra_debugs_debug_mlag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int zebra_debugs_debug_mlag_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_ip_addrs_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_ip_addrs_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_ip_addrs_label_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_ip_addrs_label_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_ip_addrs_ip4_peer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_ip_addrs_ip4_peer_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_multicast_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_multicast_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_link_detect_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_link_detect_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_shutdown_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_shutdown_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_zebra_bandwidth_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_zebra_bandwidth_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_route_map_entry_match_condition_ipv4_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_route_map_entry_match_condition_ipv6_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_route_map_entry_match_condition_source_protocol_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_match_condition_source_protocol_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_route_map_entry_match_condition_source_instance_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_match_condition_source_instance_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_route_map_entry_set_action_source_v4_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_set_action_source_v4_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_route_map_entry_set_action_source_v6_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_route_map_entry_set_action_source_v6_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+struct yang_data *
+lib_interface_zebra_state_up_count_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_down_count_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_zif_type_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_ptm_status_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_vlan_id_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_vni_id_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_remote_vtep_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_interface_zebra_state_mcast_group_get_elem(const char *xpath,
+ const void *list_entry);
+int lib_vrf_ribs_rib_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_vrf_ribs_rib_destroy(enum nb_event event, const struct lyd_node *dnode);
+const void *lib_vrf_ribs_rib_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_route_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *
+lib_vrf_ribs_rib_route_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_prefix_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_protocol_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_protocol_v6_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *lib_vrf_ribs_rib_route_vrf_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_distance_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_metric_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *lib_vrf_ribs_rib_route_tag_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_selected_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_installed_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_failed_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_queued_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_internal_flags_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_internal_status_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_uptime_get_elem(const char *xpath,
+ const void *list_entry);
+const void *
+lib_vrf_ribs_rib_route_nexthop_group_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_route_nexthop_group_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_route_nexthop_group_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_nexthop_group_name_get_elem(const char *xpath,
+ const void *list_entry);
+const void *lib_vrf_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next(
+ const void *parent_list_entry, const void *list_entry);
+int lib_vrf_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+int lib_vrf_ribs_rib_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_vrf_ribs_rib_destroy(enum nb_event event, const struct lyd_node *dnode);
+const void *lib_vrf_ribs_rib_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_route_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *
+lib_vrf_ribs_rib_route_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_prefix_get_elem(const char *xpath,
+ const void *list_entry);
+const void *
+lib_vrf_ribs_rib_route_route_entry_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int lib_vrf_ribs_rib_route_route_entry_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_route_route_entry_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_protocol_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_instance_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_distance_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_metric_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_tag_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_selected_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_installed_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_failed_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_queued_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_uptime_get_elem(const char *xpath,
+ const void *list_entry);
+const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next(
+ const void *parent_list_entry, const void *list_entry);
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
+ const char *xpath, const void *list_entry);
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
+ const void *parent_list_entry, const void *list_entry);
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
+ const char *xpath, const void *list_entry);
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
+ const void *parent_list_entry, const void *list_entry);
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
+ const char *xpath, const void *list_entry);
+
+#endif
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
new file mode 100644
index 0000000000..311922f2ef
--- /dev/null
+++ b/zebra/zebra_nb_config.c
@@ -0,0 +1,1672 @@
+/*
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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
+ */
+
+#include <zebra.h>
+
+#include "lib/log.h"
+#include "lib/northbound.h"
+#include "libfrr.h"
+#include "lib/command.h"
+#include "lib/routemap.h"
+#include "zebra/zebra_nb.h"
+#include "zebra/rib.h"
+#include "zebra_nb.h"
+#include "zebra/interface.h"
+#include "zebra/connected.h"
+
+/*
+ * XPath: /frr-zebra:zebra/mcast-rpf-lookup
+ */
+int zebra_mcast_rpf_lookup_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/ip-forwarding
+ */
+int zebra_ip_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_ip_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/ipv6-forwarding
+ */
+int zebra_ipv6_forwarding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_ipv6_forwarding_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/workqueue-hold-timer
+ */
+int zebra_workqueue_hold_timer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/zapi-packets
+ */
+int zebra_zapi_packets_modify(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/table-id
+ */
+int zebra_import_kernel_table_table_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_import_kernel_table_table_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/distance
+ */
+int zebra_import_kernel_table_distance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/import-kernel-table/route-map
+ */
+int zebra_import_kernel_table_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_import_kernel_table_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/allow-external-route-update
+ */
+int zebra_allow_external_route_update_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_allow_external_route_update_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/dplane-queue-limit
+ */
+int zebra_dplane_queue_limit_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping
+ */
+int zebra_vrf_vni_mapping_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_vrf_vni_mapping_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping/vni-id
+ */
+int zebra_vrf_vni_mapping_vni_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_vrf_vni_mapping_vni_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/vrf-vni-mapping/prefix-only
+ */
+int zebra_vrf_vni_mapping_prefix_only_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_vrf_vni_mapping_prefix_only_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-events
+ */
+int zebra_debugs_debug_events_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_events_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-send
+ */
+int zebra_debugs_debug_zapi_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_zapi_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-recv
+ */
+int zebra_debugs_debug_zapi_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_zapi_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-zapi-detail
+ */
+int zebra_debugs_debug_zapi_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_zapi_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel
+ */
+int zebra_debugs_debug_kernel_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_kernel_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-send
+ */
+int zebra_debugs_debug_kernel_msg_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_kernel_msg_send_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-recv
+ */
+int zebra_debugs_debug_kernel_msg_recv_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_kernel_msg_recv_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-rib
+ */
+int zebra_debugs_debug_rib_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_rib_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-rib-detail
+ */
+int zebra_debugs_debug_rib_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_rib_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-fpm
+ */
+int zebra_debugs_debug_fpm_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_fpm_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-nht
+ */
+int zebra_debugs_debug_nht_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_nht_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-nht-detail
+ */
+int zebra_debugs_debug_nht_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_nht_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-mpls
+ */
+int zebra_debugs_debug_mpls_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_mpls_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-vxlan
+ */
+int zebra_debugs_debug_vxlan_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_vxlan_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-pw
+ */
+int zebra_debugs_debug_pw_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_pw_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-dplane
+ */
+int zebra_debugs_debug_dplane_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_dplane_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-dplane-detail
+ */
+int zebra_debugs_debug_dplane_detail_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_dplane_detail_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-zebra:zebra/debugs/debug-mlag
+ */
+int zebra_debugs_debug_mlag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int zebra_debugs_debug_mlag_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs
+ */
+int lib_interface_zebra_ip_addrs_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct prefix prefix;
+ char buf[PREFIX_STRLEN] = {0};
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ // addr_family = yang_dnode_get_enum(dnode, "./address-family");
+ yang_dnode_get_prefix(&prefix, dnode, "./ip-prefix");
+ apply_mask(&prefix);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (prefix.family == AF_INET
+ && ipv4_martian(&prefix.u.prefix4)) {
+ zlog_debug("invalid address %s",
+ prefix2str(&prefix, buf, sizeof(buf)));
+ return NB_ERR_VALIDATION;
+ } else if (prefix.family == AF_INET6
+ && ipv6_martian(&prefix.u.prefix6)) {
+ zlog_debug("invalid address %s",
+ prefix2str(&prefix, buf, sizeof(buf)));
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ if (prefix.family == AF_INET)
+ if_ip_address_install(ifp, &prefix, NULL, NULL);
+ else if (prefix.family == AF_INET6)
+ if_ipv6_address_install(ifp, &prefix, NULL);
+
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_ip_addrs_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct interface *ifp;
+ struct prefix prefix;
+ struct connected *ifc;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_prefix(&prefix, dnode, "./ip-prefix");
+ apply_mask(&prefix);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (prefix.family == AF_INET) {
+ /* Check current interface address. */
+ ifc = connected_check_ptp(ifp, &prefix, NULL);
+ if (!ifc) {
+ zlog_debug("interface %s Can't find address\n",
+ ifp->name);
+ return NB_ERR_VALIDATION;
+ }
+ } else if (prefix.family == AF_INET6) {
+ /* Check current interface address. */
+ ifc = connected_check(ifp, &prefix);
+ if (!ifc) {
+ zlog_debug("interface can't find address %s",
+ ifp->name);
+ return NB_ERR_VALIDATION;
+ }
+ } else
+ return NB_ERR_VALIDATION;
+
+ /* This is not configured address. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
+ zlog_debug("interface %s not configured", ifp->name);
+ return NB_ERR_VALIDATION;
+ }
+
+ /* This is not real address or interface is not active. */
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED)
+ || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
+ listnode_delete(ifp->connected, ifc);
+ connected_free(&ifc);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ if_ip_address_uinstall(ifp, &prefix);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label
+ */
+int lib_interface_zebra_ip_addrs_label_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_ip_addrs_label_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer
+ */
+int lib_interface_zebra_ip_addrs_ip4_peer_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_ip_addrs_ip4_peer_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/multicast
+ */
+int lib_interface_zebra_multicast_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+
+ if_multicast_set(ifp);
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_multicast_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+
+ if_multicast_unset(ifp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-detect
+ */
+int lib_interface_zebra_link_detect_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+ bool link_detect;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ link_detect = yang_dnode_get_bool(dnode, "./link-detect");
+
+ if_linkdetect(ifp, link_detect);
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_link_detect_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+ bool link_detect;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ link_detect = yang_dnode_get_bool(dnode, "./link-detect");
+
+ if_linkdetect(ifp, link_detect);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/shutdown
+ */
+int lib_interface_zebra_shutdown_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+
+ if_shutdown(ifp);
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_shutdown_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct interface *ifp;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+
+ if_no_shutdown(ifp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/bandwidth
+ */
+int lib_interface_zebra_bandwidth_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+ uint32_t bandwidth;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ bandwidth = yang_dnode_get_uint32(dnode, "./bandwidth");
+
+ ifp->bandwidth = bandwidth;
+
+ /* force protocols to recalculate routes due to cost change */
+ if (if_is_operative(ifp))
+ zebra_interface_up_update(ifp);
+
+ return NB_OK;
+}
+
+int lib_interface_zebra_bandwidth_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct interface *ifp;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+
+ ifp->bandwidth = 0;
+
+ /* force protocols to recalculate routes due to cost change */
+ if (if_is_operative(ifp))
+ zebra_interface_up_update(ifp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib
+ */
+int lib_vrf_ribs_rib_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_vrf_ribs_rib_destroy(enum nb_event event, const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* TODO: implement me. */
+ break;
+ }
+
+ return NB_OK;
+}
+
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length
+ */
+int lib_route_map_entry_match_condition_ipv4_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *length;
+ int condition, rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ length = yang_dnode_get_string(dnode, NULL);
+ condition = yang_dnode_get_enum(dnode, "../frr-route-map:condition");
+
+ /* Set destroy information. */
+ switch (condition) {
+ case 100: /* ipv4-prefix-length */
+ rhc->rhc_rule = "ip address prefix-len";
+ break;
+
+ case 102: /* ipv4-next-hop-prefix-length */
+ rhc->rhc_rule = "ip next-hop prefix-len";
+ break;
+ }
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, rhc->rhc_rule, length,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length
+ */
+int lib_route_map_entry_match_condition_ipv6_prefix_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *length;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ length = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "ipv6 address prefix-len";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "ipv6 address prefix-len",
+ length, RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol
+ */
+int lib_route_map_entry_match_condition_source_protocol_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ type = yang_dnode_get_string(dnode, NULL);
+ if (proto_name2num(type) == -1) {
+ zlog_warn("%s: invalid protocol: %s", __func__, type);
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "source-protocol";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "source-protocol", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_source_protocol_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance
+ */
+int lib_route_map_entry_match_condition_source_instance_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ const char *type;
+ int rv;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_mhook = generic_match_delete;
+ rhc->rhc_rule = "source-instance";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ rv = generic_match_add(NULL, rhc->rhc_rmi, "source-instance", type,
+ RMAP_EVENT_MATCH_ADDED);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_source_instance_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4
+ */
+int lib_route_map_entry_set_action_source_v4_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ struct interface *pif = NULL;
+ const char *source;
+ struct vrf *vrf;
+ struct prefix p;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ memset(&p, 0, sizeof(p));
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ if (zebra_check_addr(&p) == 0) {
+ zlog_warn("%s: invalid IPv4 address: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ pif = if_lookup_exact_address(&p.u.prefix4, AF_INET,
+ vrf->vrf_id);
+ if (pif != NULL)
+ break;
+ }
+ if (pif == NULL) {
+ zlog_warn("%s: is not a local adddress: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ source = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "src";
+
+ rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_source_v4_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6
+ */
+int lib_route_map_entry_set_action_source_v6_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct routemap_hook_context *rhc;
+ struct interface *pif = NULL;
+ const char *source;
+ struct vrf *vrf;
+ struct prefix p;
+ int rv;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ memset(&p, 0, sizeof(p));
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ if (zebra_check_addr(&p) == 0) {
+ zlog_warn("%s: invalid IPv6 address: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ pif = if_lookup_exact_address(&p.u.prefix6, AF_INET6,
+ vrf->vrf_id);
+ if (pif != NULL)
+ break;
+ }
+ if (pif == NULL) {
+ zlog_warn("%s: is not a local adddress: %s", __func__,
+ yang_dnode_get_string(dnode, NULL));
+ return NB_ERR_VALIDATION;
+ }
+ return NB_OK;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ return NB_OK;
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ /* Add configuration. */
+ rhc = nb_running_get_entry(dnode, NULL, true);
+ source = yang_dnode_get_string(dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "src";
+
+ rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_source_v6_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return lib_route_map_entry_set_destroy(event, dnode);
+}
diff --git a/zebra/zebra_nb_rpcs.c b/zebra/zebra_nb_rpcs.c
new file mode 100644
index 0000000000..cf8efe40a4
--- /dev/null
+++ b/zebra/zebra_nb_rpcs.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2020 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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
+ */
+
+#include <zebra.h>
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "zebra/zebra_nb.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+
+/*
+ * XPath: /frr-zebra:clear-evpn-dup-addr
+ */
+int clear_evpn_dup_addr_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ struct zebra_vrf *zvrf;
+ int ret = NB_OK;
+ struct yang_data *yang_dup_choice = NULL, *yang_dup_vni = NULL,
+ *yang_dup_ip = NULL, *yang_dup_mac = NULL;
+
+ yang_dup_choice = yang_data_list_find(input, "%s/%s", xpath,
+ "input/clear-dup-choice");
+
+ zvrf = zebra_vrf_get_evpn();
+
+ if (yang_dup_choice
+ && strcmp(yang_dup_choice->value, "all-case") == 0) {
+ zebra_vxlan_clear_dup_detect_vni_all(zvrf);
+ } else {
+ vni_t vni;
+ struct ipaddr host_ip = {.ipa_type = IPADDR_NONE};
+ struct ethaddr mac;
+
+ yang_dup_vni = yang_data_list_find(
+ input, "%s/%s", xpath,
+ "input/clear-dup-choice/single-case/vni-id");
+ if (yang_dup_vni) {
+ vni = yang_str2uint32(yang_dup_vni->value);
+
+ yang_dup_mac = yang_data_list_find(
+ input, "%s/%s", xpath,
+ "input/clear-dup-choice/single-case/vni-id/mac-addr");
+ yang_dup_ip = yang_data_list_find(
+ input, "%s/%s", xpath,
+ "input/clear-dup-choice/single-case/vni-id/vni-ipaddr");
+
+ if (yang_dup_mac) {
+ yang_str2mac(yang_dup_mac->value, &mac);
+ ret = zebra_vxlan_clear_dup_detect_vni_mac(
+ zvrf, vni, &mac);
+ } else if (yang_dup_ip) {
+ yang_str2ip(yang_dup_ip->value, &host_ip);
+ ret = zebra_vxlan_clear_dup_detect_vni_ip(
+ zvrf, vni, &host_ip);
+ } else
+ ret = zebra_vxlan_clear_dup_detect_vni(zvrf,
+ vni);
+ }
+ }
+ ret = (ret != CMD_SUCCESS) ? NB_ERR : NB_OK;
+
+ return ret;
+}
+
+/*
+ * XPath: /frr-zebra:get-route-information
+ */
+int get_route_information_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-v6-mroute-info
+ */
+int get_v6_mroute_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vrf-info
+ */
+int get_vrf_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vrf-vni-info
+ */
+int get_vrf_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-info
+ */
+int get_evpn_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-vni-info
+ */
+int get_vni_info_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-vni-rmac
+ */
+int get_evpn_vni_rmac_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-vni-nexthops
+ */
+int get_evpn_vni_nexthops_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-macs
+ */
+int get_evpn_macs_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-evpn-arp-cache
+ */
+int get_evpn_arp_cache_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-pbr-ipset
+ */
+int get_pbr_ipset_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-pbr-iptable
+ */
+int get_pbr_iptable_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
+
+/*
+ * XPath: /frr-zebra:get-debugs
+ */
+int get_debugs_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ /* TODO: implement me. */
+ return NB_ERR_NOT_FOUND;
+}
diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c
new file mode 100644
index 0000000000..9036bdf0f6
--- /dev/null
+++ b/zebra/zebra_nb_state.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2020 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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
+ */
+
+#include <zebra.h>
+#include "northbound.h"
+#include "libfrr.h"
+#include "zebra_nb.h"
+#include "zebra/interface.h"
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/up-count
+ */
+struct yang_data *
+lib_interface_zebra_state_up_count_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+
+ zebra_if = ifp->info;
+
+ return yang_data_new_uint16(xpath, zebra_if->up_count);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/down-count
+ */
+struct yang_data *
+lib_interface_zebra_state_down_count_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+
+ zebra_if = ifp->info;
+
+ return yang_data_new_uint16(xpath, zebra_if->down_count);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/zif-type
+ */
+struct yang_data *
+lib_interface_zebra_state_zif_type_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/ptm-status
+ */
+struct yang_data *
+lib_interface_zebra_state_ptm_status_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/vlan-id
+ */
+struct yang_data *
+lib_interface_zebra_state_vlan_id_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+ struct zebra_l2info_vlan *vlan_info;
+
+ if (!IS_ZEBRA_IF_VLAN(ifp))
+ return NULL;
+
+ zebra_if = ifp->info;
+ vlan_info = &zebra_if->l2info.vl;
+
+ return yang_data_new_uint16(xpath, vlan_info->vid);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/vni-id
+ */
+struct yang_data *
+lib_interface_zebra_state_vni_id_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+ struct zebra_l2info_vxlan *vxlan_info;
+
+ if (!IS_ZEBRA_IF_VXLAN(ifp))
+ return NULL;
+
+ zebra_if = ifp->info;
+ vxlan_info = &zebra_if->l2info.vxl;
+
+ return yang_data_new_uint32(xpath, vxlan_info->vni);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/remote-vtep
+ */
+struct yang_data *
+lib_interface_zebra_state_remote_vtep_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+ struct zebra_l2info_vxlan *vxlan_info;
+
+ if (!IS_ZEBRA_IF_VXLAN(ifp))
+ return NULL;
+
+ zebra_if = ifp->info;
+ vxlan_info = &zebra_if->l2info.vxl;
+
+ return yang_data_new_ipv4(xpath, &vxlan_info->vtep_ip);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/mcast-group
+ */
+struct yang_data *
+lib_interface_zebra_state_mcast_group_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct interface *ifp = list_entry;
+ struct zebra_if *zebra_if;
+ struct zebra_l2info_vxlan *vxlan_info;
+
+ if (!IS_ZEBRA_IF_VXLAN(ifp))
+ return NULL;
+
+ zebra_if = ifp->info;
+ vxlan_info = &zebra_if->l2info.vxl;
+
+ return yang_data_new_ipv4(xpath, &vxlan_info->mcast_grp);
+}
+
+const void *lib_vrf_ribs_rib_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *lib_vrf_ribs_rib_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route
+ */
+const void *lib_vrf_ribs_rib_route_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *
+lib_vrf_ribs_rib_route_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/prefix
+ */
+struct yang_data *lib_vrf_ribs_rib_route_prefix_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry
+ */
+const void *
+lib_vrf_ribs_rib_route_route_entry_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_route_route_entry_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *lib_vrf_ribs_rib_route_route_entry_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/protocol
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_protocol_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/instance
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_instance_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/distance
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_distance_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/metric
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_metric_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/tag
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_tag_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/selected
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_selected_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/installed
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_installed_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/failed
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_failed_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/queued
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_queued_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-flags
+ */
+struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-status
+ */
+struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/uptime
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_uptime_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group
+ */
+const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next(
+ const void *parent_list_entry, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys(
+ const void *list_entry, struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/name
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop
+ */
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
+ const void *parent_list_entry, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
+ const void *list_entry, struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry
+ */
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
+ const void *parent_list_entry, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
+ const void *list_entry, struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NB_OK;
+}
+
+const void *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight
+ */
+struct yang_data *
+lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index ea4b07a87d..77a9a7c368 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -143,7 +143,7 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
void *tail = (void *)((char *)nlh + NETLINK_ALIGN(nlh->nlmsg_len));
struct nlattr *attr;
- for (attr = (struct nlattr *)((char *)buf + offset);
+ for (attr = (struct nlattr *)(buf + offset);
NETLINK_NLATTR_LEN(tail, attr) >= sizeof(struct nlattr)
&& attr->nla_len >= sizeof(struct nlattr)
&& attr->nla_len <= NETLINK_NLATTR_LEN(tail, attr);
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index dc0af050d7..de044c0ea0 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -63,6 +63,9 @@ static struct nhg_hash_entry *
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
static void depends_decrement_free(struct nhg_connected_tree_head *head);
+static struct nhg_backup_info *
+nhg_backup_copy(const struct nhg_backup_info *orig);
+
static void nhg_connected_free(struct nhg_connected *dep)
{
@@ -295,7 +298,7 @@ static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
static void
zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
- struct nhg_connected_tree_head nhg_depends)
+ struct nhg_connected_tree_head *nhg_depends)
{
struct nhg_connected *rb_node_dep = NULL;
@@ -304,31 +307,58 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
* for now. Otherwise, their might be a time trade-off for repeated
* alloc/frees as startup.
*/
- nhe->nhg_depends = nhg_depends;
+ nhe->nhg_depends = *nhg_depends;
/* Attach backpointer to anything that it depends on */
zebra_nhg_dependents_init(nhe);
if (!zebra_nhg_depends_is_empty(nhe)) {
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u), dep %p (%u)",
+ __func__, nhe, nhe->id,
+ rb_node_dep->nhe,
+ rb_node_dep->nhe->id);
+
zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
}
}
+}
- /* Add the ifp now if its not a group or recursive and has ifindex */
- if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
- && nhe->nhg.nexthop->ifindex) {
- struct interface *ifp = NULL;
+/* Init an nhe, for use in a hash lookup for example */
+void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
+ const struct nexthop *nh)
+{
+ memset(nhe, 0, sizeof(struct nhg_hash_entry));
+ nhe->vrf_id = VRF_DEFAULT;
+ nhe->type = ZEBRA_ROUTE_NHG;
+ nhe->afi = AFI_UNSPEC;
- ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
- nhe->nhg.nexthop->vrf_id);
- if (ifp)
- zebra_nhg_set_if(nhe, ifp);
- else
- flog_err(
- EC_ZEBRA_IF_LOOKUP_FAILED,
- "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
- nhe->nhg.nexthop->ifindex,
- nhe->nhg.nexthop->vrf_id, nhe->id);
+ /* There are some special rules that apply to groups representing
+ * a single nexthop.
+ */
+ if (nh && (nh->next == NULL)) {
+ switch (nh->type) {
+ case (NEXTHOP_TYPE_IFINDEX):
+ case (NEXTHOP_TYPE_BLACKHOLE):
+ /*
+ * This switch case handles setting the afi different
+ * for ipv4/v6 routes. Ifindex/blackhole nexthop
+ * objects cannot be ambiguous, they must be Address
+ * Family specific. If we get here, we will either use
+ * the AF of the route, or the one we got passed from
+ * here from the kernel.
+ */
+ nhe->afi = afi;
+ break;
+ case (NEXTHOP_TYPE_IPV4_IFINDEX):
+ case (NEXTHOP_TYPE_IPV4):
+ nhe->afi = AFI_IP;
+ break;
+ case (NEXTHOP_TYPE_IPV6_IFINDEX):
+ case (NEXTHOP_TYPE_IPV6):
+ nhe->afi = AFI_IP6;
+ break;
+ }
}
}
@@ -341,7 +371,7 @@ struct nhg_hash_entry *zebra_nhg_alloc(void)
return nhe;
}
-static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy,
+static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *orig,
uint32_t id)
{
struct nhg_hash_entry *nhe;
@@ -350,14 +380,18 @@ static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy,
nhe->id = id;
- nexthop_group_copy(&(nhe->nhg), &(copy->nhg));
+ nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
- nhe->vrf_id = copy->vrf_id;
- nhe->afi = copy->afi;
- nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG;
+ nhe->vrf_id = orig->vrf_id;
+ nhe->afi = orig->afi;
+ nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
nhe->refcnt = 0;
nhe->dplane_ref = zebra_router_get_next_sequence();
+ /* Copy backup info also, if present */
+ if (orig->backup_info)
+ nhe->backup_info = nhg_backup_copy(orig->backup_info);
+
return nhe;
}
@@ -372,7 +406,25 @@ static void *zebra_nhg_hash_alloc(void *arg)
/* Mark duplicate nexthops in a group at creation time. */
nexthop_group_mark_duplicates(&(nhe->nhg));
- zebra_nhg_connect_depends(nhe, copy->nhg_depends);
+ zebra_nhg_connect_depends(nhe, &(copy->nhg_depends));
+
+ /* Add the ifp now if it's not a group or recursive and has ifindex */
+ if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
+ && nhe->nhg.nexthop->ifindex) {
+ struct interface *ifp = NULL;
+
+ ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
+ nhe->nhg.nexthop->vrf_id);
+ if (ifp)
+ zebra_nhg_set_if(nhe, ifp);
+ else
+ flog_err(
+ EC_ZEBRA_IF_LOOKUP_FAILED,
+ "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
+ nhe->nhg.nexthop->ifindex,
+ nhe->nhg.nexthop->vrf_id, nhe->id);
+ }
+
zebra_nhg_insert_id(nhe);
return nhe;
@@ -381,12 +433,17 @@ static void *zebra_nhg_hash_alloc(void *arg)
uint32_t zebra_nhg_hash_key(const void *arg)
{
const struct nhg_hash_entry *nhe = arg;
+ uint32_t val, key = 0x5a351234;
+
+ val = nexthop_group_hash(&(nhe->nhg));
+ if (nhe->backup_info) {
+ val = jhash_2words(val,
+ nexthop_group_hash(
+ &(nhe->backup_info->nhe->nhg)),
+ key);
+ }
- uint32_t key = 0x5a351234;
-
- key = jhash_3words(nhe->vrf_id, nhe->afi,
- nexthop_group_hash(&(nhe->nhg)),
- key);
+ key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
return key;
}
@@ -398,6 +455,46 @@ uint32_t zebra_nhg_id_key(const void *arg)
return nhe->id;
}
+/* Helper with common nhg/nhe nexthop comparison logic */
+static bool nhg_compare_nexthops(const struct nexthop *nh1,
+ const struct nexthop *nh2)
+{
+ assert(nh1 != NULL && nh2 != NULL);
+
+ /*
+ * 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(nh1->flags, NEXTHOP_FLAG_ACTIVE)
+ != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
+ if (!nexthop_same(nh1, nh2))
+ return false;
+
+ return true;
+}
+
bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
{
const struct nhg_hash_entry *nhe1 = arg1;
@@ -415,45 +512,48 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
- /* Nexthops should be sorted */
+ /* Nexthops should be in-order, so we simply compare them in-place */
for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
- nexthop1 || nexthop2;
+ nexthop1 && nexthop2;
nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
- if (nexthop1 && !nexthop2)
- return false;
- if (!nexthop1 && nexthop2)
+ if (!nhg_compare_nexthops(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;
+ /* Check for unequal list lengths */
+ if (nexthop1 || nexthop2)
+ return false;
+
+ /* If there's no backup info, comparison is done. */
+ if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
+ return true;
+
+ /* Compare backup info also - test the easy things first */
+ if (nhe1->backup_info && (nhe2->backup_info == NULL))
+ return false;
+ if (nhe2->backup_info && (nhe1->backup_info == NULL))
+ return false;
+
+ /* Compare number of backups before actually comparing any */
+ for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
+ nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
+ nexthop1 && nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+ ;
+ }
+
+ /* Did we find the end of one list before the other? */
+ if (nexthop1 || nexthop2)
+ return false;
+
+ /* Have to compare the backup nexthops */
+ for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
+ nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
+ nexthop1 && nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
- if (!nexthop_same(nexthop1, nexthop2))
+ if (!nhg_compare_nexthops(nexthop1, nexthop2))
return false;
}
@@ -512,29 +612,185 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
resolved_ng.nexthop = nh;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: head %p, nh %pNHv",
+ __func__, nhg_depends, nh);
+
depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, depend,
+ depend ? depend->id : 0);
+
if (depend)
depends_add(nhg_depends, depend);
}
+/*
+ * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
+ * has an id value, that's used. Create a new global/shared nhe if not found.
+ */
+static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
+ struct nhg_hash_entry *lookup,
+ struct nhg_connected_tree_head *nhg_depends,
+ afi_t afi)
+{
+ bool created = false;
+ bool recursive = false;
+ struct nhg_hash_entry *newnhe, *backup_nhe;
+ struct nexthop *nh = NULL;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p",
+ __func__, lookup->id, lookup,
+ lookup->vrf_id, lookup->type,
+ nhg_depends);
+
+ if (lookup->id)
+ (*nhe) = zebra_nhg_lookup_id(lookup->id);
+ else
+ (*nhe) = hash_lookup(zrouter.nhgs, lookup);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: lookup => %p (%u)",
+ __func__, (*nhe),
+ (*nhe) ? (*nhe)->id : 0);
+
+ /* If we found an existing object, we're done */
+ if (*nhe)
+ goto done;
+
+ /* We're going to create/insert a new nhe:
+ * assign the next global id value if necessary.
+ */
+ if (lookup->id == 0)
+ lookup->id = ++id_counter;
+ newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+ created = true;
+
+ /* Mail back the new object */
+ *nhe = newnhe;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => created %p (%u)", __func__, newnhe,
+ newnhe->id);
+
+ /* Only hash/lookup the depends if the first lookup
+ * fails to find something. This should hopefully save a
+ * lot of cycles for larger ecmp sizes.
+ */
+ if (nhg_depends) {
+ /* If you don't want to hash on each nexthop in the
+ * nexthop group struct you can pass the depends
+ * directly. Kernel-side we do this since it just looks
+ * them up via IDs.
+ */
+ zebra_nhg_connect_depends(newnhe, nhg_depends);
+ goto done;
+ }
+
+ /* Prepare dependency relationships if this is not a
+ * singleton nexthop. There are two cases: a single
+ * recursive nexthop, where we need a relationship to the
+ * resolving nexthop; or a group of nexthops, where we need
+ * relationships with the corresponding singletons.
+ */
+ zebra_nhg_depends_init(lookup);
+
+ nh = newnhe->nhg.nexthop;
+
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
+ SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
+
+ if (nh->next == NULL) {
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ /* Single recursive nexthop */
+ handle_recursive_depend(&newnhe->nhg_depends,
+ nh->resolved, afi);
+ recursive = true;
+ }
+ } else {
+ /* List of nexthops */
+ for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: depends NH %pNHv %s",
+ __func__, nh,
+ CHECK_FLAG(nh->flags,
+ NEXTHOP_FLAG_RECURSIVE) ?
+ "(R)" : "");
+
+ depends_find_add(&newnhe->nhg_depends, nh, afi);
+ }
+ }
+
+ if (recursive)
+ SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
+
+ if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
+ zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
+ goto done;
+
+ /* If there are backup nexthops, add them to the backup
+ * depends tree. The rules here are a little different.
+ */
+ recursive = false;
+ backup_nhe = newnhe->backup_info->nhe;
+
+ nh = backup_nhe->nhg.nexthop;
+
+ /* Singleton recursive NH */
+ if (nh->next == NULL &&
+ CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: backup depend NH %pNHv (R)",
+ __func__, nh);
+
+ /* Single recursive nexthop */
+ handle_recursive_depend(&backup_nhe->nhg_depends,
+ nh->resolved, afi);
+ recursive = true;
+ } else {
+ /* One or more backup NHs */
+ for (; nh; nh = nh->next) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: backup depend NH %pNHv %s",
+ __func__, nh,
+ CHECK_FLAG(nh->flags,
+ NEXTHOP_FLAG_RECURSIVE) ?
+ "(R)" : "");
+
+ depends_find_add(&backup_nhe->nhg_depends,
+ nh, afi);
+ }
+ }
+
+ if (recursive)
+ SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
+
+done:
+
+ return created;
+}
+
+/*
+ * Lookup or create an nhe, based on an nhg or an nhe id.
+ */
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
struct nexthop_group *nhg,
struct nhg_connected_tree_head *nhg_depends,
vrf_id_t vrf_id, afi_t afi, int type)
{
struct nhg_hash_entry lookup = {};
-
- uint32_t old_id_counter = id_counter;
-
bool created = false;
- bool recursive = false;
- /*
- * If it has an id at this point, we must have gotten it from the kernel
- */
- lookup.id = id ? id : ++id_counter;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
+ __func__, id, nhg, vrf_id, type,
+ nhg_depends);
+ /* Use a temporary nhe and call into the superset/common code */
+ lookup.id = id;
lookup.type = type ? type : ZEBRA_ROUTE_NHG;
lookup.nhg = *nhg;
@@ -567,53 +823,8 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
}
}
- if (id)
- (*nhe) = zebra_nhg_lookup_id(id);
- else
- (*nhe) = hash_lookup(zrouter.nhgs, &lookup);
-
- /* If it found an nhe in our tables, this new ID is unused */
- if (*nhe)
- id_counter = old_id_counter;
+ created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi);
- if (!(*nhe)) {
- /* Only hash/lookup the depends if the first lookup
- * fails to find something. This should hopefully save a
- * lot of cycles for larger ecmp sizes.
- */
- if (nhg_depends)
- /* If you don't want to hash on each nexthop in the
- * nexthop group struct you can pass the depends
- * directly. Kernel-side we do this since it just looks
- * them up via IDs.
- */
- lookup.nhg_depends = *nhg_depends;
- else {
- if (nhg->nexthop->next) {
- zebra_nhg_depends_init(&lookup);
-
- /* If its a group, create a dependency tree */
- struct nexthop *nh = NULL;
-
- for (nh = nhg->nexthop; nh; nh = nh->next)
- depends_find_add(&lookup.nhg_depends,
- nh, afi);
- } else if (CHECK_FLAG(nhg->nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE)) {
- zebra_nhg_depends_init(&lookup);
- handle_recursive_depend(&lookup.nhg_depends,
- nhg->nexthop->resolved,
- afi);
- recursive = true;
- }
- }
-
- (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
- created = true;
-
- if (recursive)
- SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
- }
return created;
}
@@ -629,6 +840,10 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
@@ -807,6 +1022,9 @@ done:
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
+
/* Remove it from any lists it may be on */
zebra_nhg_depends_release(nhe);
zebra_nhg_dependents_release(nhe);
@@ -872,6 +1090,10 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
lookup = zebra_nhg_lookup_id(id);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, count %d, lookup => %p",
+ __func__, id, count, lookup);
+
if (lookup) {
/* This is already present in our table, hence an update
* that we did not initate.
@@ -919,6 +1141,11 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
*/
kernel_nhe = zebra_nhg_copy(nhe, id);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: copying kernel nhe (%u), dup of %u",
+ __func__, id, nhe->id);
+
zebra_nhg_insert_id(kernel_nhe);
zebra_nhg_set_unhashable(kernel_nhe);
} else if (zebra_nhg_contains_unhashable(nhe)) {
@@ -926,10 +1153,18 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
* depend, so lets mark this group as unhashable as well
* and release it from the non-ID hash.
*/
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) unhashable",
+ __func__, nhe, nhe->id);
+
hash_release(zrouter.nhgs, nhe);
zebra_nhg_set_unhashable(nhe);
} else {
/* It actually created a new nhe */
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) is new",
+ __func__, nhe, nhe->id);
+
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
}
@@ -1038,6 +1273,10 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
{
struct nhg_ctx *ctx = NULL;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv, id %u, count %d",
+ __func__, nh, id, (int)count);
+
if (id > id_counter)
/* Increase our counter so we don't try to create
* an ID that already exists
@@ -1111,12 +1350,17 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
/* The copy may have allocated labels; free them if necessary. */
nexthop_del_labels(&lookup);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p (%u)",
+ __func__, nh, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
{
struct nhg_hash_entry *nhe = NULL;
+ char rbuf[10];
if (!nh)
goto done;
@@ -1124,10 +1368,18 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
/* We are separating these functions out to increase handling speed
* in the non-recursive case (by not alloc/freeing)
*/
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
nhe = depends_find_recursive(nh, afi);
- else
+ strlcpy(rbuf, "(R)", sizeof(rbuf));
+ } else {
nhe = depends_find_singleton(nh, afi);
+ rbuf[0] = '\0';
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv %s => %p (%u)",
+ __func__, nh, rbuf,
+ nhe, nhe ? nhe->id : 0);
done:
return nhe;
@@ -1136,6 +1388,10 @@ done:
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: head %p nh %pNHv",
+ __func__, head, depend->nhg.nexthop);
+
/* If NULL is returned, it was successfully added and
* needs to have its refcnt incremented.
*
@@ -1154,6 +1410,10 @@ depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
depend = depends_find(nh, afi);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nh %pNHv => %p",
+ __func__, nh, depend);
+
if (depend)
depends_add(head, depend);
@@ -1179,7 +1439,7 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head)
nhg_connected_tree_free(head);
}
-/* Rib-side, you get a nexthop group struct */
+/* Find an nhe based on a list of nexthops */
struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
{
@@ -1195,13 +1455,105 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => nhe %p (%u)",
+ __func__, nhe, nhe ? nhe->id : 0);
+
+ return nhe;
+}
+
+/* Find an nhe based on a route's nhe */
+struct nhg_hash_entry *
+zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
+ flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
+ "No nexthop passed to %s", __func__);
+ return NULL;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: rt_nhe %p (%u)", __func__, rt_nhe, rt_nhe->id);
+
+ zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: => nhe %p (%u)",
+ __func__, nhe, nhe ? nhe->id : 0);
+
return nhe;
}
+/*
+ * Allocate backup nexthop info object. Typically these are embedded in
+ * nhg_hash_entry objects.
+ */
+struct nhg_backup_info *zebra_nhg_backup_alloc(void)
+{
+ struct nhg_backup_info *p;
+
+ p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
+
+ p->nhe = zebra_nhg_alloc();
+
+ /* Identify the embedded group used to hold the list of backups */
+ SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
+
+ return p;
+}
+
+/*
+ * Free backup nexthop info object, deal with any embedded allocations
+ */
+void zebra_nhg_backup_free(struct nhg_backup_info **p)
+{
+ if (p && *p) {
+ if ((*p)->nhe)
+ zebra_nhg_free((*p)->nhe);
+
+ XFREE(MTYPE_NHG, (*p));
+ }
+}
+
+/* Accessor for backup nexthop group */
+struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
+{
+ struct nexthop_group *p = NULL;
+
+ if (nhe) {
+ if (nhe->backup_info && nhe->backup_info->nhe)
+ p = &(nhe->backup_info->nhe->nhg);
+ }
+
+ return p;
+}
+
+/*
+ * Helper to return a copy of a backup_info - note that this is a shallow
+ * copy, meant to be used when creating a new nhe from info passed in with
+ * a route e.g.
+ */
+static struct nhg_backup_info *
+nhg_backup_copy(const struct nhg_backup_info *orig)
+{
+ struct nhg_backup_info *b;
+
+ b = zebra_nhg_backup_alloc();
+
+ /* Copy list of nexthops */
+ nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
+
+ return b;
+}
+
static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
{
nexthops_free(nhe->nhg.nexthop);
+ zebra_nhg_backup_free(&nhe->backup_info);
+
/* Decrement to remove connection ref */
nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
nhg_connected_tree_free(&nhe->nhg_depends);
@@ -1210,6 +1562,17 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
void zebra_nhg_free(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ /* Group or singleton? */
+ if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
+ zlog_debug("%s: nhe %p (%u), refcnt %d",
+ __func__, nhe, nhe->id, nhe->refcnt);
+ else
+ zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
+ __func__, nhe, nhe->id, nhe->refcnt,
+ nhe->nhg.nexthop);
+ }
+
if (nhe->refcnt)
zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
@@ -1225,6 +1588,11 @@ void zebra_nhg_hash_free(void *p)
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) %d => %d",
+ __func__, nhe, nhe->id, nhe->refcnt,
+ nhe->refcnt - 1);
+
nhe->refcnt--;
if (!zebra_nhg_depends_is_empty(nhe))
@@ -1236,6 +1604,11 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) %d => %d",
+ __func__, nhe, nhe->id, nhe->refcnt,
+ nhe->refcnt + 1);
+
nhe->refcnt++;
if (!zebra_nhg_depends_is_empty(nhe))
@@ -1385,6 +1758,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
nexthop->resolved = NULL;
re->nexthop_mtu = 0;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p, nexthop %pNHv",
+ __func__, re, nexthop);
+
/*
* If the kernel has sent us a NEW route, then
* by golly gee whiz it's a good route.
@@ -1533,6 +1910,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|| nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = newhop->ifindex;
}
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
return 1;
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
@@ -1543,18 +1926,24 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
nexthop_set_resolved(afi, newhop, nexthop);
resolved = 1;
}
+
if (resolved)
re->nexthop_mtu = match->mtu;
-
- if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
+ else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
" %s: Recursion failed to find",
__func__);
+
return resolved;
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
@@ -1565,6 +1954,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!nexthop_valid_resolve(nexthop, newhop))
continue;
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: STATIC match %p (%u), newhop %pNHv",
+ __func__, match,
+ match->nhe->id, newhop);
+
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
nexthop_set_resolved(afi, newhop, nexthop);
@@ -1683,11 +2077,11 @@ static unsigned nexthop_active_check(struct route_node *rn,
default:
break;
}
+
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Unable to find a active nexthop",
- __func__);
+ zlog_debug(" %s: Unable to find active nexthop",
+ __func__);
return 0;
}
@@ -1768,45 +2162,37 @@ done:
}
/*
- * Iterate over all nexthops of the given RIB entry and refresh their
- * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
- * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
- *
- * Return value is the new number of active nexthops.
+ * Process a list of nexthops, given the head of the list, determining
+ * whether each one is ACTIVE/installable at this time.
*/
-int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+static uint32_t nexthop_list_active_update(struct route_node *rn,
+ struct route_entry *re,
+ struct nexthop *nexthop)
{
- struct nexthop_group new_grp = {};
- struct nexthop *nexthop;
union g_addr prev_src;
unsigned int prev_active, new_active;
ifindex_t prev_index;
- uint8_t curr_active = 0;
+ uint32_t counter = 0;
- afi_t rt_afi = family2afi(rn->p.family);
-
- UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-
- /* Copy over the nexthops in current state */
- nexthop_group_copy(&new_grp, &(re->nhe->nhg));
-
- for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
+ /* Process nexthops one-by-one */
+ for ( ; nexthop; nexthop = nexthop->next) {
/* No protocol daemon provides src and so we're skipping
- * tracking it */
+ * tracking it
+ */
prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
/*
* We need to respect the multipath_num here
* as that what we should be able to install from
- * a multipath perpsective should not be a data plane
+ * a multipath perspective should not be a data plane
* decision point.
*/
new_active =
nexthop_active_check(rn, re, nexthop);
- if (new_active && curr_active >= zrouter.multipath_num) {
+ if (new_active && counter >= zrouter.multipath_num) {
struct nexthop *nh;
/* Set it and its resolved nexthop as inactive. */
@@ -1817,7 +2203,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
}
if (new_active)
- curr_active++;
+ counter++;
/* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active || prev_index != nexthop->ifindex
@@ -1833,14 +2219,79 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
}
+ return counter;
+}
+
+/*
+ * Iterate over all nexthops of the given RIB entry and refresh their
+ * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
+ * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
+ *
+ * Return value is the new number of active nexthops.
+ */
+int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+{
+ struct nhg_hash_entry *curr_nhe;
+ uint32_t curr_active = 0, backup_active = 0;
+
+ afi_t rt_afi = family2afi(rn->p.family);
+
+ UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+
+ /* Make a local copy of the existing nhe, so we don't work on/modify
+ * the shared nhe.
+ */
+ curr_nhe = zebra_nhg_copy(re->nhe, re->nhe->id);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
+ __func__, re, re->nhe, re->nhe->id,
+ curr_nhe);
+
+ /* Clear the existing id, if any: this will avoid any confusion
+ * if the id exists, and will also force the creation
+ * of a new nhe reflecting the changes we may make in this local copy.
+ */
+ curr_nhe->id = 0;
+
+ /* Process nexthops */
+ curr_active = nexthop_list_active_update(rn, re, curr_nhe->nhg.nexthop);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p curr_active %u", __func__, re,
+ curr_active);
+
+ /* If there are no backup nexthops, we are done */
+ if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
+ goto backups_done;
+
+ backup_active = nexthop_list_active_update(
+ rn, re, zebra_nhg_get_backup_nhg(curr_nhe)->nexthop);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p backup_active %u", __func__, re,
+ backup_active);
+
+backups_done:
+
+ /*
+ * Ref or create an nhe that matches the current state of the
+ * nexthop(s).
+ */
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
struct nhg_hash_entry *new_nhe = NULL;
- new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
+ new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
+ __func__, re, re->nhe,
+ re->nhe->id, new_nhe, new_nhe->id);
route_entry_update_nhe(re, new_nhe);
}
+
/* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
* flag where appropriate.
*/
@@ -1848,11 +2299,11 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
zebra_nhg_set_valid_if_active(re->nhe);
/*
- * Do not need these nexthops anymore since they
- * were either copied over into an nhe or not
+ * Do not need the old / copied nhe anymore since it
+ * was either copied over into a new nhe or not
* used at all.
*/
- nexthops_free(new_grp.nexthop);
+ zebra_nhg_free(curr_nhe);
return curr_active;
}
@@ -1950,6 +2401,16 @@ static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
}
}
+ if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
+ goto done;
+
+ /* TODO -- For now, we are not trying to use or install any
+ * backup info in this nexthop-id path: we aren't prepared
+ * to use the backups here yet. We're just debugging what we find.
+ */
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: skipping backup nhe", __func__);
+
done:
return i;
}
@@ -2036,7 +2497,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
id = dplane_ctx_get_nhe_id(ctx);
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
ctx, dplane_op2str(op), id, dplane_res2str(status));
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index dc3a47c020..0a9e97ab48 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -50,6 +50,9 @@ struct nhg_hash_entry {
struct nexthop_group nhg;
+ /* If supported, a mapping of backup nexthops. */
+ struct nhg_backup_info *backup_info;
+
/* If this is not a group, it
* will be a single nexthop
* and must have an interface
@@ -72,6 +75,7 @@ struct nhg_hash_entry {
* faster with ID's.
*/
struct nhg_connected_tree_head nhg_depends, nhg_dependents;
+
/*
* Is this nexthop group valid, ie all nexthops are fully resolved.
* What is fully resolved? It's a nexthop that is either self contained
@@ -102,11 +106,25 @@ struct nhg_hash_entry {
* from the kernel. Therefore, it is unhashable.
*/
#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
+
+/*
+ * Backup nexthop support - identify groups that are backups for
+ * another group.
+ */
+#define NEXTHOP_GROUP_BACKUP (1 << 5)
+
};
/* Was this one we created, either this session or previously? */
#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+/*
+ * Backup nexthops: this is a group object itself, so
+ * that the backup nexthops can use the same code as a normal object.
+ */
+struct nhg_backup_info {
+ struct nhg_hash_entry *nhe;
+};
enum nhg_ctx_op_e {
NHG_CTX_OP_NONE = 0,
@@ -162,13 +180,26 @@ bool zebra_nhg_kernel_nexthops_enabled(void);
/**
* NHE abstracted tree functions.
- * Use these where possible instead of the direct ones access ones.
+ * Use these where possible instead of direct access.
*/
struct nhg_hash_entry *zebra_nhg_alloc(void);
void zebra_nhg_free(struct nhg_hash_entry *nhe);
/* In order to clear a generic hash, we need a generic api, sigh. */
void zebra_nhg_hash_free(void *p);
+/* Init an nhe, for use in a hash lookup for example. There's some fuzziness
+ * if the nhe represents only a single nexthop, so we try to capture that
+ * variant also.
+ */
+void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
+ const struct nexthop *nh);
+
+/* Allocate, free backup nexthop info objects */
+struct nhg_backup_info *zebra_nhg_backup_alloc(void);
+void zebra_nhg_backup_free(struct nhg_backup_info **p);
+
+struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe);
+
extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe);
extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe);
@@ -203,10 +234,14 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
/* Del via kernel */
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
-/* Find via route creation */
+/* Find an nhe based on a nexthop_group */
extern struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
+/* Find an nhe based on a route's nhe, used during route creation */
+struct nhg_hash_entry *
+zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
+
/* Reference counter functions */
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 3287176ef5..4e51437337 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -126,6 +126,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
kernel_init(zns);
interface_list(zns);
route_read(zns);
+ kernel_read_pbr_rules(zns);
/* Initiate Table Manager per ZNS */
table_manager_enable(ns_id);
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 6728567e6e..c049aa14f6 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -431,32 +431,51 @@ static void *pbr_rule_alloc_intern(void *arg)
return new;
}
+static int pbr_rule_release(struct zebra_pbr_rule *rule)
+{
+ struct zebra_pbr_rule *lookup;
+
+ lookup = hash_lookup(zrouter.rules_hash, rule);
+
+ if (!lookup)
+ return -ENOENT;
+
+ hash_release(zrouter.rules_hash, lookup);
+ XFREE(MTYPE_TMP, lookup);
+
+ return 0;
+}
+
void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
{
- struct zebra_pbr_rule *unique =
- pbr_rule_lookup_unique(rule);
+ struct zebra_pbr_rule *found;
- (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
- (void)kernel_add_pbr_rule(rule);
- /*
- * Rule Replace semantics, if we have an old, install the
- * new rule, look above, and then delete the old
+ /**
+ * Check if we already have it (this checks via a unique ID, walking
+ * over the hash table, not via a hash operation).
*/
- if (unique)
- zebra_pbr_del_rule(unique);
+ found = pbr_rule_lookup_unique(rule);
+
+ (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
+
+ /* If found, this is an update */
+ if (found) {
+ (void)kernel_update_pbr_rule(found, rule);
+
+ if (pbr_rule_release(found))
+ zlog_debug(
+ "%s: Rule being updated we know nothing about",
+ __PRETTY_FUNCTION__);
+
+ } else
+ (void)kernel_add_pbr_rule(rule);
}
void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
{
- struct zebra_pbr_rule *lookup;
-
- lookup = hash_lookup(zrouter.rules_hash, rule);
(void)kernel_del_pbr_rule(rule);
- if (lookup) {
- hash_release(zrouter.rules_hash, lookup);
- XFREE(MTYPE_TMP, lookup);
- } else
+ if (pbr_rule_release(rule))
zlog_debug("%s: Rule being deleted we know nothing about",
__func__);
}
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index b7fbc9b7d5..83797b9521 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -183,6 +183,13 @@ extern enum zebra_dplane_result kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
extern enum zebra_dplane_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule);
/*
+ * Update specified rule for a specific interface.
+ */
+extern enum zebra_dplane_result
+kernel_update_pbr_rule(struct zebra_pbr_rule *old_rule,
+ struct zebra_pbr_rule *new_rule);
+
+/*
* Get to know existing PBR rules in the kernel - typically called at startup.
*/
extern void kernel_read_pbr_rules(struct zebra_ns *zns);
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 610a052c31..7a14f6304f 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -547,13 +547,18 @@ static int zebra_pw_config(struct vty *vty)
return write;
}
+static int zebra_pw_config(struct vty *vty);
static struct cmd_node pw_node = {
- PW_NODE, "%s(config-pw)# ", 1,
+ .name = "pw",
+ .node = PW_NODE,
+ .parent_node = CONFIG_NODE,
+ .prompt = "%s(config-pw)# ",
+ .config_write = zebra_pw_config,
};
void zebra_pw_vty_init(void)
{
- install_node(&pw_node, zebra_pw_config);
+ install_node(&pw_node);
install_default(PW_NODE);
install_element(CONFIG_NODE, &pseudowire_if_cmd);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index dc54dee785..2dbe907751 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -213,7 +213,7 @@ static void route_entry_attach_ref(struct route_entry *re,
int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
{
- struct nhg_hash_entry *old = NULL;
+ struct nhg_hash_entry *old;
int ret = 0;
if (new == NULL) {
@@ -223,7 +223,7 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
goto done;
}
- if (re->nhe_id != new->id) {
+ if ((re->nhe_id != 0) && (re->nhe_id != new->id)) {
old = re->nhe;
route_entry_attach_ref(re, new);
@@ -261,7 +261,7 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
p.prefixlen = IPV6_MAX_PREFIXLEN;
}
- rn = route_node_match(table, (struct prefix *)&p);
+ rn = route_node_match(table, &p);
while (rn) {
rib_dest_t *dest;
@@ -348,8 +348,8 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
char buf[BUFSIZ];
inet_ntop(AF_INET, &addr, buf, BUFSIZ);
- zlog_debug("%s: %s: vrf: %u found %s, using %s",
- __func__, buf, vrf_id,
+ zlog_debug("%s: %s: vrf: %s(%u) found %s, using %s", __func__,
+ buf, vrf_id_to_name(vrf_id), vrf_id,
mre ? (ure ? "MRIB+URIB" : "MRIB")
: ure ? "URIB" : "nothing",
re == ure ? "URIB" : re == mre ? "MRIB" : "none");
@@ -659,13 +659,14 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
char buf1[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
- zlog_debug("%u:%s has Nexthop(%s) Type: %s depending on it, evaluating %u:%u",
- zvrf->vrf->vrf_id,
- srcdest_rnode2str(rn, buf1,
- sizeof(buf1)),
- prefix2str(p, buf2, sizeof(buf2)),
- rnh_type2str(rnh->type),
- seq, rnh->seqno);
+ zlog_debug(
+ "%s(%u):%s has Nexthop(%s) Type: %s depending on it, evaluating %u:%u",
+ zvrf_name(zvrf), zvrf_id(zvrf),
+ srcdest_rnode2str(rn, buf1,
+ sizeof(buf1)),
+ prefix2str(p, buf2, sizeof(buf2)),
+ rnh_type2str(rnh->type), seq,
+ rnh->seqno);
}
/*
@@ -753,8 +754,8 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%u:%s: Adding route rn %p, re %p (%s)",
- zvrf_id(zvrf), buf, rn, new,
+ zlog_debug("%s(%u):%s: Adding route rn %p, re %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, new,
zebra_route_string(new->type));
}
@@ -776,8 +777,8 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%u:%s: Deleting route rn %p, re %p (%s)",
- zvrf_id(zvrf), buf, rn, old,
+ zlog_debug("%s(%u):%s: Deleting route rn %p, re %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, old,
zebra_route_string(old->type));
}
@@ -829,15 +830,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%u:%s: Updating route rn %p, re %p (%s) old %p (%s)",
- zvrf_id(zvrf), buf, rn, new,
+ "%s(%u):%s: Updating route rn %p, re %p (%s) old %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf),
+ buf, rn, new,
zebra_route_string(new->type),
old,
zebra_route_string(old->type));
else
zlog_debug(
- "%u:%s: Updating route rn %p, re %p (%s)",
- zvrf_id(zvrf), buf, rn, new,
+ "%s(%u):%s: Updating route rn %p, re %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf),
+ buf, rn, new,
zebra_route_string(new->type));
}
@@ -867,15 +870,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%u:%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive",
- zvrf_id(zvrf), buf, rn, new,
+ "%s(%u):%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive",
+ zvrf_name(zvrf), zvrf_id(zvrf),
+ buf, rn, new,
zebra_route_string(new->type),
old,
zebra_route_string(old->type));
else
zlog_debug(
- "%u:%s: Deleting route rn %p, re %p (%s) - nexthop inactive",
- zvrf_id(zvrf), buf, rn, new,
+ "%s(%u):%s: Deleting route rn %p, re %p (%s) - nexthop inactive",
+ zvrf_name(zvrf), zvrf_id(zvrf),
+ buf, rn, new,
zebra_route_string(new->type));
}
@@ -990,6 +995,7 @@ static void rib_process(struct route_node *rn)
char buf[SRCDEST2STR_BUFFER];
rib_dest_t *dest;
struct zebra_vrf *zvrf = NULL;
+ struct vrf *vrf;
const struct prefix *p, *src_p;
srcdest_rnode_prefixes(rn, &p, &src_p);
@@ -1003,11 +1009,14 @@ static void rib_process(struct route_node *rn)
vrf_id = zvrf_id(zvrf);
}
+ vrf = vrf_lookup_by_id(vrf_id);
+
if (IS_ZEBRA_DEBUG_RIB)
srcdest_rnode2str(rn, buf, sizeof(buf));
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%u:%s: Processing rn %p", vrf_id, buf, rn);
+ zlog_debug("%s(%u):%s: Processing rn %p", VRF_LOGNAME(vrf),
+ vrf_id, buf, rn);
/*
* we can have rn's that have a NULL info pointer
@@ -1021,10 +1030,10 @@ static void rib_process(struct route_node *rn)
RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%u:%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
- vrf_id, buf, re, zebra_route_string(re->type),
- re->status, re->flags, re->distance,
- re->metric);
+ "%s(%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+ VRF_LOGNAME(vrf), vrf_id, buf, re,
+ zebra_route_string(re->type), re->status,
+ re->flags, re->distance, re->metric);
/* Currently selected re. */
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -1065,9 +1074,11 @@ static void rib_process(struct route_node *rn)
if (re != old_selected) {
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s: %u:%s: imported via import-table but denied "
+ "%s: %s(%u):%s: imported via import-table but denied "
"by the ip protocol table route-map",
- __func__, vrf_id, buf);
+ __func__,
+ VRF_LOGNAME(vrf),
+ vrf_id, buf);
rib_unlink(rn, re);
} else
SET_FLAG(re->status,
@@ -1118,9 +1129,9 @@ static void rib_process(struct route_node *rn)
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
zlog_debug(
- "%u:%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
- vrf_id, buf, (void *)old_selected, (void *)new_selected,
- (void *)old_fib, (void *)new_fib);
+ "%s(%u):%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
+ VRF_LOGNAME(vrf), vrf_id, buf, (void *)old_selected,
+ (void *)new_selected, (void *)old_fib, (void *)new_fib);
}
/* Buffer ROUTE_ENTRY_CHANGED here, because it will get cleared if
@@ -1191,8 +1202,8 @@ static void zebra_rib_evaluate_mpls(struct route_node *rn)
if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS)) {
if (IS_ZEBRA_DEBUG_MPLS)
zlog_debug(
- "%u: Scheduling all LSPs upon RIB completion",
- zvrf_id(zvrf));
+ "%s(%u): Scheduling all LSPs upon RIB completion",
+ zvrf_name(zvrf), zvrf_id(zvrf));
zebra_mpls_lsp_schedule(zvrf);
mpls_unmark_lsps_for_processing(rn);
}
@@ -1299,6 +1310,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
bool is_selected = false; /* Is 're' currently the selected re? */
bool changed_p = false; /* Change to nexthops? */
rib_dest_t *dest;
+ struct vrf *vrf;
+
+ vrf = vrf_lookup_by_id(re->vrf_id);
/* Note well: only capturing the prefix string if debug is enabled here;
* unconditional log messages will have to generate the string.
@@ -1311,8 +1325,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
is_selected = (re == dest->selected_fib);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("update_from_ctx: %u:%s: %sSELECTED",
- re->vrf_id, dest_str, (is_selected ? "" : "NOT "));
+ zlog_debug("update_from_ctx: %s(%u):%s: %sSELECTED",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ (is_selected ? "" : "NOT "));
/* Update zebra's nexthop FIB flag for each nexthop that was installed.
* If the installed set differs from the set requested by the rib/owner,
@@ -1325,11 +1340,10 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
* Let's assume the nexthops are ordered here to save time.
*/
if (nexthop_group_equal(&re->fib_ng, dplane_ctx_get_ng(ctx)) == false) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%u:%s update_from_ctx: notif nh and fib nh mismatch",
- re->vrf_id, dest_str);
- }
+ "%s(%u):%s update_from_ctx: notif nh and fib nh mismatch",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
matched = false;
} else
@@ -1338,8 +1352,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
/* If the new FIB set matches the existing FIB set, we're done. */
if (matched) {
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%u:%s update_from_ctx(): existing fib nhg, no change",
- re->vrf_id, dest_str);
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): existing fib nhg, no change",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
goto done;
} else if (re->fib_ng.nexthop) {
@@ -1347,8 +1362,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
* Free stale fib list and move on to check the rib nhg.
*/
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%u:%s update_from_ctx(): replacing fib nhg",
- re->vrf_id, dest_str);
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): replacing fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
nexthops_free(re->fib_ng.nexthop);
re->fib_ng.nexthop = NULL;
@@ -1356,8 +1372,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
changed_p = true;
} else {
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%u:%s update_from_ctx(): no fib nhg",
- re->vrf_id, dest_str);
+ zlog_debug("%s(%u):%s update_from_ctx(): no fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str);
}
/*
@@ -1437,9 +1453,10 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
/* If all nexthops were processed, we're done */
if (matched) {
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%u:%s update_from_ctx(): rib nhg matched, changed '%s'",
- re->vrf_id, dest_str,
- (changed_p ? "true" : "false"));
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): rib nhg matched, changed '%s'",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ (changed_p ? "true" : "false"));
goto done;
}
@@ -1449,9 +1466,10 @@ no_nexthops:
* create a fib-specific nexthop-group
*/
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%u:%s update_from_ctx(): changed %s, adding new fib nhg",
- re->vrf_id, dest_str,
- (changed_p ? "true" : "false"));
+ zlog_debug(
+ "%s(%u):%s update_from_ctx(): changed %s, adding new fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ (changed_p ? "true" : "false"));
ctxnhg = dplane_ctx_get_ng(ctx);
@@ -1489,10 +1507,12 @@ rib_find_rn_from_ctx(const struct zebra_dplane_ctx *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",
- dplane_ctx_get_afi(ctx),
- dplane_ctx_get_safi(ctx),
- dplane_ctx_get_vrf(ctx));
+ zlog_debug(
+ "Failed to find route for ctx: no table for afi %d, safi %d, vrf %s(%u)",
+ dplane_ctx_get_afi(ctx),
+ dplane_ctx_get_safi(ctx),
+ vrf_id_to_name(dplane_ctx_get_vrf(ctx)),
+ dplane_ctx_get_vrf(ctx));
}
goto done;
}
@@ -1515,6 +1535,7 @@ done:
static void rib_process_result(struct zebra_dplane_ctx *ctx)
{
struct zebra_vrf *zvrf = NULL;
+ struct vrf *vrf;
struct route_node *rn = NULL;
struct route_entry *re = NULL, *old_re = NULL, *rib;
bool is_update = false;
@@ -1526,6 +1547,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
bool fib_changed = false;
zvrf = vrf_info_lookup(dplane_ctx_get_vrf(ctx));
+ vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
dest_pfx = dplane_ctx_get_dest(ctx);
/* Note well: only capturing the prefix string if debug is enabled here;
@@ -1538,8 +1560,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
rn = rib_find_rn_from_ctx(ctx);
if (rn == NULL) {
if (IS_ZEBRA_DEBUG_DPLANE) {
- zlog_debug("Failed to process dplane results: no route for %u:%s",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "Failed to process dplane results: no route for %s(%u):%s",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
}
goto done;
}
@@ -1550,9 +1574,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
status = dplane_ctx_get_status(ctx);
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("%u:%s Processing dplane ctx %p, op %s result %s",
- dplane_ctx_get_vrf(ctx), dest_str, ctx,
- dplane_op2str(op), dplane_res2str(status));
+ zlog_debug(
+ "%s(%u):%s Processing dplane ctx %p, op %s result %s",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str,
+ ctx, dplane_op2str(op), dplane_res2str(status));
/*
* Update is a bit of a special case, where we may have both old and new
@@ -1590,9 +1615,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (re) {
if (re->dplane_sequence != seq) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("%u:%s Stale dplane result for re %p",
- dplane_ctx_get_vrf(ctx),
- dest_str, re);
+ zlog_debug(
+ "%s(%u):%s Stale dplane result for re %p",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx), dest_str, re);
} else
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
}
@@ -1600,9 +1626,11 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (old_re) {
if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("%u:%s Stale dplane result for old_re %p",
- dplane_ctx_get_vrf(ctx),
- dest_str, old_re);
+ zlog_debug(
+ "%s(%u):%s Stale dplane result for old_re %p",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx), dest_str,
+ old_re);
} else
UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
}
@@ -1639,10 +1667,11 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (!fib_changed) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("%u:%s no fib change for re",
- dplane_ctx_get_vrf(
- ctx),
- dest_str);
+ zlog_debug(
+ "%s(%u):%s no fib change for re",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx),
+ dest_str);
}
/* Redistribute */
@@ -1677,10 +1706,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
zsend_route_notify_owner(re, dest_pfx,
ZAPI_ROUTE_FAIL_INSTALL);
- zlog_warn("%u:%s: Route install failed",
- dplane_ctx_get_vrf(ctx),
- prefix2str(dest_pfx,
- dest_str, sizeof(dest_str)));
+ zlog_warn("%s(%u):%s: Route install failed",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ prefix2str(dest_pfx, dest_str,
+ sizeof(dest_str)));
}
break;
case DPLANE_OP_ROUTE_DELETE:
@@ -1706,10 +1735,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
zsend_route_notify_owner_ctx(ctx,
ZAPI_ROUTE_REMOVE_FAIL);
- zlog_warn("%u:%s: Route Deletion failure",
- dplane_ctx_get_vrf(ctx),
- prefix2str(dest_pfx,
- dest_str, sizeof(dest_str)));
+ zlog_warn("%s(%u):%s: Route Deletion failure",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ prefix2str(dest_pfx, dest_str,
+ sizeof(dest_str)));
}
/*
@@ -1747,6 +1776,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
{
struct route_node *rn = NULL;
struct route_entry *re = NULL;
+ struct vrf *vrf;
struct nexthop *nexthop;
char dest_str[PREFIX_STRLEN] = "";
const struct prefix *dest_pfx, *src_pfx;
@@ -1755,6 +1785,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB;
int start_count, end_count;
dest_pfx = dplane_ctx_get_dest(ctx);
+ vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
/* Note well: only capturing the prefix string if debug is enabled here;
* unconditional log messages will have to generate the string.
@@ -1766,8 +1797,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
rn = rib_find_rn_from_ctx(ctx);
if (rn == NULL) {
if (debug_p) {
- zlog_debug("Failed to process dplane notification: no routes for %u:%s",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "Failed to process dplane notification: no routes for %s(%u):%s",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
}
goto done;
}
@@ -1776,8 +1809,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
if (debug_p)
- zlog_debug("%u:%s Processing dplane notif ctx %p",
- dplane_ctx_get_vrf(ctx), dest_str, ctx);
+ zlog_debug("%s(%u):%s Processing dplane notif ctx %p",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str,
+ ctx);
/*
* Take a pass through the routes, look for matches with the context
@@ -1791,10 +1825,11 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* No match? Nothing we can do */
if (re == NULL) {
if (debug_p)
- zlog_debug("%u:%s Unable to process dplane notification: no entry for type %s",
- dplane_ctx_get_vrf(ctx), dest_str,
- zebra_route_string(
- dplane_ctx_get_type(ctx)));
+ zlog_debug(
+ "%s(%u):%s Unable to process dplane notification: no entry for type %s",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str,
+ zebra_route_string(dplane_ctx_get_type(ctx)));
goto done;
}
@@ -1824,17 +1859,21 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
if (debug_p)
- zlog_debug("%u:%s dplane notif, uninstalled type %s route",
- dplane_ctx_get_vrf(ctx), dest_str,
- zebra_route_string(
- dplane_ctx_get_type(ctx)));
+ zlog_debug(
+ "%s(%u):%s dplane notif, uninstalled type %s route",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx), dest_str,
+ zebra_route_string(
+ dplane_ctx_get_type(ctx)));
} else {
/* At least report on the event. */
if (debug_p)
- zlog_debug("%u:%s dplane notif, but type %s not selected_fib",
- dplane_ctx_get_vrf(ctx), dest_str,
- zebra_route_string(
- dplane_ctx_get_type(ctx)));
+ zlog_debug(
+ "%s(%u):%s dplane notif, but type %s not selected_fib",
+ VRF_LOGNAME(vrf),
+ dplane_ctx_get_vrf(ctx), dest_str,
+ zebra_route_string(
+ dplane_ctx_get_type(ctx)));
}
goto done;
}
@@ -1859,8 +1898,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (!fib_changed) {
if (debug_p)
- zlog_debug("%u:%s dplane notification: rib_update returns FALSE",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "%s(%u):%s dplane notification: rib_update returns FALSE",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
}
/*
@@ -1879,8 +1920,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
*/
if (start_count > 0 && end_count > 0) {
if (debug_p)
- zlog_debug("%u:%s applied nexthop changes from dplane notification",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "%s(%u):%s applied nexthop changes from dplane notification",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
/* Changed nexthops - update kernel/others */
dplane_route_notif_update(rn, re,
@@ -1888,8 +1931,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
} else if (start_count == 0 && end_count > 0) {
if (debug_p)
- zlog_debug("%u:%s installed transition from dplane notification",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "%s(%u):%s installed transition from dplane notification",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
/* We expect this to be the selected route, so we want
* to tell others about this transition.
@@ -1904,8 +1949,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
} else if (start_count > 0 && end_count == 0) {
if (debug_p)
- zlog_debug("%u:%s un-installed transition from dplane notification",
- dplane_ctx_get_vrf(ctx), dest_str);
+ zlog_debug(
+ "%s(%u):%s un-installed transition from dplane notification",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dest_str);
/* Transition from _something_ installed to _nothing_
* installed.
@@ -1970,8 +2017,8 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex)
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rnode, buf, sizeof(buf));
- zlog_debug("%u:%s: rn %p dequeued from sub-queue %u",
- zvrf ? zvrf_id(zvrf) : 0, buf, rnode, qindex);
+ zlog_debug("%s(%u):%s: rn %p dequeued from sub-queue %u",
+ zvrf_name(zvrf), zvrf_id(zvrf), buf, rnode, qindex);
}
if (rnode->info)
@@ -2338,7 +2385,6 @@ static void rib_addnode(struct route_node *rn,
void rib_unlink(struct route_node *rn, struct route_entry *re)
{
rib_dest_t *dest;
- struct nhg_hash_entry *nhe = NULL;
assert(rn && re);
@@ -2353,11 +2399,10 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
if (dest->selected_fib == re)
dest->selected_fib = NULL;
- if (re->nhe_id) {
- nhe = zebra_nhg_lookup_id(re->nhe_id);
- if (nhe)
- zebra_nhg_decrement_ref(nhe);
- } else if (re->nhe->nhg.nexthop)
+ if (re->nhe && re->nhe_id) {
+ assert(re->nhe->id == re->nhe_id);
+ zebra_nhg_decrement_ref(re->nhe);
+ } else if (re->nhe && re->nhe->nhg.nexthop)
nexthops_free(re->nhe->nhg.nexthop);
nexthops_free(re->fib_ng.nexthop);
@@ -2385,9 +2430,9 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%u:%s: Freeing route rn %p, re %p (%s)",
- re->vrf_id, buf, rn, re,
- zebra_route_string(re->type));
+ zlog_debug("%s(%u):%s: Freeing route rn %p, re %p (%s)",
+ vrf_id_to_name(re->vrf_id), re->vrf_id, buf,
+ rn, re, zebra_route_string(re->type));
}
rib_unlink(rn, re);
@@ -2396,11 +2441,75 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
}
}
+/*
+ * Helper that debugs a single nexthop within a route-entry
+ */
+static void _route_entry_dump_nh(const struct route_entry *re,
+ const char *straddr,
+ const struct nexthop *nexthop)
+{
+ char nhname[PREFIX_STRLEN];
+ char backup_str[50];
+ char wgt_str[50];
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ sprintf(nhname, "Blackhole");
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+ sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ /* fallthrough */
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ inet_ntop(AF_INET6, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
+ break;
+ }
+
+ backup_str[0] = '\0';
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ snprintf(backup_str, sizeof(backup_str), "backup %d,",
+ (int)nexthop->backup_idx);
+ }
+
+ wgt_str[0] = '\0';
+ if (nexthop->weight)
+ snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight);
+
+ zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s",
+ straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
+ nexthop->ifindex, vrf ? vrf->name : "Unknown",
+ nexthop->vrf_id,
+ wgt_str, backup_str,
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
+ ? "ACTIVE "
+ : ""),
+ (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
+ ? "FIB "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ ? "RECURSIVE "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
+ ? "ONLINK "
+ : ""),
+ (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
+ ? "DUPLICATE "
+ : ""));
+
+}
+
/* This function dumps the contents of a given RE entry into
* standard debug log. Calling function name and IP prefix in
* question are passed as 1st and 2nd arguments.
*/
-
void _route_entry_dump(const char *func, union prefixconstptr pp,
union prefixconstptr src_pp,
const struct route_entry *re)
@@ -2409,9 +2518,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
bool is_srcdst = src_p && src_p->prefixlen;
char straddr[PREFIX_STRLEN];
char srcaddr[PREFIX_STRLEN];
- char nhname[PREFIX_STRLEN];
struct nexthop *nexthop;
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
+ struct nexthop_group *nhg;
zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func,
(const void *)re, prefix2str(pp, straddr, sizeof(straddr)),
@@ -2422,78 +2531,48 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
straddr, (unsigned long)re->uptime, re->type, re->instance,
re->table);
- zlog_debug(
- "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
- straddr, re->metric, re->mtu, re->distance, re->flags, re->status);
+ zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
+ straddr, re->metric, re->mtu, re->distance, re->flags,
+ re->status);
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
nexthop_group_nexthop_num(&(re->nhe->nhg)),
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
- for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
- struct interface *ifp;
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ /* Dump nexthops */
+ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop))
+ _route_entry_dump_nh(re, straddr, nexthop);
- switch (nexthop->type) {
- case NEXTHOP_TYPE_BLACKHOLE:
- sprintf(nhname, "Blackhole");
- break;
- case NEXTHOP_TYPE_IFINDEX:
- ifp = if_lookup_by_index(nexthop->ifindex,
- nexthop->vrf_id);
- sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
- break;
- case NEXTHOP_TYPE_IPV4:
- /* fallthrough */
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- inet_ntop(AF_INET, &nexthop->gate, nhname,
- INET6_ADDRSTRLEN);
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- inet_ntop(AF_INET6, &nexthop->gate, nhname,
- INET6_ADDRSTRLEN);
- break;
- }
- zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s",
- straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
- nexthop->ifindex, vrf ? vrf->name : "Unknown",
- nexthop->vrf_id,
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
- ? "ACTIVE "
- : ""),
- (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
- ? "FIB "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
- ? "RECURSIVE "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
- ? "ONLINK "
- : ""),
- (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
- ? "DUPLICATE "
- : ""));
+ if (zebra_nhg_get_backup_nhg(re->nhe)) {
+ zlog_debug("%s: backup nexthops:", straddr);
+
+ nhg = zebra_nhg_get_backup_nhg(re->nhe);
+ for (ALL_NEXTHOPS_PTR(nhg, nexthop))
+ _route_entry_dump_nh(re, straddr, nexthop);
}
+
zlog_debug("%s: dump complete", straddr);
}
-/* This is an exported helper to rtm_read() to dump the strange
+/*
+ * This is an exported helper to rtm_read() to dump the strange
* RE entry found by rib_lookup_ipv4_route()
*/
-
void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
{
struct route_table *table;
struct route_node *rn;
struct route_entry *re;
+ struct vrf *vrf;
char prefix_buf[INET_ADDRSTRLEN];
+ vrf = vrf_lookup_by_id(vrf_id);
+
/* Lookup table. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
if (!table) {
flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
- "%s:%u zebra_vrf_table() returned NULL", __func__,
- vrf_id);
+ "%s:%s(%u) zebra_vrf_table() returned NULL", __func__,
+ VRF_LOGNAME(vrf), vrf_id);
return;
}
@@ -2502,7 +2581,8 @@ void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
/* No route for this prefix. */
if (!rn) {
- zlog_debug("%s:%u lookup failed for %s", __func__, vrf_id,
+ zlog_debug("%s:%s(%u) lookup failed for %s", __func__,
+ VRF_LOGNAME(vrf), vrf_id,
prefix2str((struct prefix *)p, prefix_buf,
sizeof(prefix_buf)));
return;
@@ -2513,9 +2593,8 @@ void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
/* let's go */
RNODE_FOREACH_RE (rn, re) {
- zlog_debug("%s:%u rn %p, re %p: %s, %s",
- __func__, vrf_id,
- (void *)rn, (void *)re,
+ zlog_debug("%s:%s(%u) rn %p, re %p: %s, %s", __func__,
+ VRF_LOGNAME(vrf), vrf_id, (void *)rn, (void *)re,
(CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
? "removed"
: "NOT removed"),
@@ -2538,9 +2617,11 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
rib_dest_t *dest;
if (NULL == (table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id))) {
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
- "%s:%u zebra_vrf_table() returned NULL", __func__,
- vrf_id);
+ "%s:%s(%u) zebra_vrf_table() returned NULL", __func__,
+ VRF_LOGNAME(vrf), vrf_id);
return;
}
@@ -2563,10 +2644,13 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
if (dest->selected_fib) {
if (IS_ZEBRA_DEBUG_RIB) {
char buf[PREFIX_STRLEN];
+ struct vrf *vrf =
+ vrf_lookup_by_id(dest->selected_fib->vrf_id);
- zlog_debug("%u:%s: freeing way for connected prefix",
- dest->selected_fib->vrf_id,
- prefix2str(&rn->p, buf, sizeof(buf)));
+ zlog_debug(
+ "%s(%u):%s: freeing way for connected prefix",
+ VRF_LOGNAME(vrf), dest->selected_fib->vrf_id,
+ prefix2str(&rn->p, buf, sizeof(buf)));
route_entry_dump(&rn->p, NULL, dest->selected_fib);
}
rib_uninstall(rn, dest->selected_fib);
@@ -2574,9 +2658,16 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
}
}
-int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p, struct route_entry *re,
- struct nexthop_group *ng)
+/*
+ * Internal route-add implementation; there are a couple of different public
+ * signatures. Callers in this path are responsible for the memory they
+ * allocate: if they allocate a nexthop_group or backup nexthop info, they
+ * must free those objects. If this returns < 0, an error has occurred and the
+ * route_entry 're' has not been captured; the caller should free that also.
+ */
+int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nhg_hash_entry *re_nhe)
{
struct nhg_hash_entry *nhe = NULL;
struct route_table *table;
@@ -2584,41 +2675,31 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct route_entry *same = NULL;
int ret = 0;
- if (!re)
- return 0;
+ if (!re || !re_nhe)
+ return -1;
assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
/* Lookup table. */
table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id,
re->table);
- if (!table) {
- if (ng)
- nexthop_group_delete(&ng);
- XFREE(MTYPE_RE, re);
- return 0;
- }
+ if (!table)
+ return -1;
- if (re->nhe_id) {
- nhe = zebra_nhg_lookup_id(re->nhe_id);
+ if (re_nhe->id > 0) {
+ nhe = zebra_nhg_lookup_id(re_nhe->id);
if (!nhe) {
flog_err(
EC_ZEBRA_TABLE_LOOKUP_FAILED,
"Zebra failed to find the nexthop hash entry for id=%u in a route entry",
- re->nhe_id);
- XFREE(MTYPE_RE, re);
+ re_nhe->id);
+
return -1;
}
} else {
- nhe = zebra_nhg_rib_find(0, ng, afi);
-
- /*
- * The nexthops got copied over into an nhe,
- * so free them now.
- */
- nexthop_group_delete(&ng);
-
+ /* Lookup nhe from route information */
+ nhe = zebra_nhg_rib_find_nhe(re_nhe, afi);
if (!nhe) {
char buf[PREFIX_STRLEN] = "";
char buf2[PREFIX_STRLEN] = "";
@@ -2631,7 +2712,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
src_p ? prefix2str(src_p, buf2, sizeof(buf2))
: "");
- XFREE(MTYPE_RE, re);
return -1;
}
}
@@ -2709,15 +2789,51 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
ret = 1;
/* Free implicit route.*/
- if (same) {
+ if (same)
rib_delnode(rn, same);
- ret = -1;
- }
route_unlock_node(rn);
return ret;
}
+/*
+ * Add a single route.
+ */
+int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nexthop_group *ng)
+{
+ int ret;
+ struct nhg_hash_entry nhe;
+
+ if (!re)
+ return -1;
+
+ /* We either need nexthop(s) or an existing nexthop id */
+ if (ng == NULL && re->nhe_id == 0)
+ return -1;
+
+ /*
+ * Use a temporary nhe to convey info to the common/main api.
+ */
+ zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL));
+ if (ng)
+ nhe.nhg.nexthop = ng->nexthop;
+ else if (re->nhe_id > 0)
+ nhe.id = re->nhe_id;
+
+ ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe);
+
+ /* In this path, the callers expect memory to be freed. */
+ nexthop_group_delete(&ng);
+
+ /* In error cases, free the route also */
+ if (ret < 0)
+ XFREE(MTYPE_RE, re);
+
+ return ret;
+}
+
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
@@ -3030,8 +3146,7 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
table->info ? afi2str(
((rib_table_info_t *)table->info)->afi)
: "Unknown",
- vrf ? vrf->name : "Unknown",
- zvrf ? zvrf->table_id : 0,
+ VRF_LOGNAME(vrf), zvrf ? zvrf->table_id : 0,
rib_update_event2str(event));
}
@@ -3188,6 +3303,9 @@ void rib_sweep_table(struct route_table *table)
if (!table)
return;
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: starting", __func__);
+
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
RNODE_FOREACH_RE_SAFE (rn, re, next) {
@@ -3234,6 +3352,9 @@ void rib_sweep_table(struct route_table *table)
rib_delnode(rn, re);
}
}
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: ends", __func__);
}
/* Sweep all RIB tables. */
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 500c2c84a1..2b3b3afbb5 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -30,6 +30,8 @@
#include "filter.h"
#include "plist.h"
#include "nexthop.h"
+#include "northbound_cli.h"
+#include "route_types.h"
#include "vrf.h"
#include "frrstr.h"
@@ -58,82 +60,6 @@ struct nh_rmap_obj {
static void zebra_route_map_set_delay_timer(uint32_t value);
-
-/* Add zebra route map rule */
-static int zebra_route_match_add(struct vty *vty, const char *command,
- const char *arg, route_map_event_t type)
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- enum rmap_compile_rets ret;
- int retval = CMD_SUCCESS;
-
- ret = route_map_add_match(index, command, arg, type);
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_SUCCESS:
- /*
- * Nothing to do here
- */
- break;
- }
-
- return retval;
-}
-
-/* Delete zebra route map rule. */
-static int zebra_route_match_delete(struct vty *vty, const char *command,
- const char *arg, route_map_event_t type)
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- enum rmap_compile_rets ret;
- int retval = CMD_SUCCESS;
- char *dep_name = NULL;
- const char *tmpstr;
- char *rmap_name = NULL;
-
- if (type != RMAP_EVENT_MATCH_DELETED) {
- /* ignore the mundane, the types without any dependency */
- if (arg == NULL) {
- if ((tmpstr = route_map_get_match_arg(index, command))
- != NULL)
- dep_name =
- XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr);
- } else {
- dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg);
- }
- rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
- }
-
- ret = route_map_delete_match(index, command, arg, type);
- switch (ret) {
- case RMAP_RULE_MISSING:
- vty_out(vty, "%% Zebra Can't find rule.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_ERROR:
- vty_out(vty, "%% Zebra Argument is malformed.\n");
- retval = CMD_WARNING_CONFIG_FAILED;
- break;
- case RMAP_COMPILE_SUCCESS:
- /*
- * Nothing to do here
- */
- break;
- }
-
- XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
- XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name);
-
- return retval;
-}
-
/* 'match tag TAG'
* Match function return 1 if match is success else return 0
*/
@@ -425,246 +351,227 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype,
return CMD_SUCCESS;
}
-DEFUN (match_ip_address_prefix_len,
- match_ip_address_prefix_len_cmd,
- "match ip address prefix-len (0-32)",
- MATCH_STR
- IP_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ match_ip_address_prefix_len, match_ip_address_prefix_len_cmd,
+ "match ip address prefix-len (0-32)$length",
+ MATCH_STR
+ IP_STR
+ "Match prefix length of IP address\n"
+ "Match prefix length of IP address\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ip address prefix-len", argv[4]->arg,
- RMAP_EVENT_MATCH_ADDED);
+ const char *xpath = "./match-condition[condition='ipv4-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv4-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ip_address_prefix_len,
- no_match_ip_address_prefix_len_cmd,
- "no match ip address prefix-len [(0-32)]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd,
+ "no match ip address prefix-len [(0-32)]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefix length of IP address\n"
+ "Match prefix length of IP address\n"
+ "Prefix length\n")
{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ip address prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
+ const char *xpath = "./match-condition[condition='ipv4-prefix-length']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (match_ipv6_address_prefix_len,
- match_ipv6_address_prefix_len_cmd,
- "match ipv6 address prefix-len (0-128)",
- MATCH_STR
- IPV6_STR
- "Match prefix length of ipv6 address\n"
- "Match prefix length of ipv6 address\n"
- "Prefix length\n")
+DEFPY(
+ match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd,
+ "match ipv6 address prefix-len (0-128)$length",
+ MATCH_STR
+ IPV6_STR
+ "Match prefix length of IPv6 address\n"
+ "Match prefix length of IPv6 address\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ipv6 address prefix-len",
- argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
+ const char *xpath = "./match-condition[condition='ipv6-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv6-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ipv6_address_prefix_len,
- no_match_ipv6_address_prefix_len_cmd,
- "no match ipv6 address prefix-len [(0-128)]",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match prefix length of ip address\n"
- "Match prefix length of ip address\n"
- "Prefix length\n")
+DEFPY(
+ no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd,
+ "no match ipv6 address prefix-len [(0-128)]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match prefix length of IPv6 address\n"
+ "Match prefix length of IPv6 address\n"
+ "Prefix length\n")
{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ipv6 address prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
+ const char *xpath = "./match-condition[condition='ipv6-prefix-length']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (match_ip_nexthop_prefix_len,
- match_ip_nexthop_prefix_len_cmd,
- "match ip next-hop prefix-len (0-32)",
- MATCH_STR
- IP_STR
- "Match prefixlen of nexthop ip address\n"
- "Match prefixlen of given nexthop\n"
- "Prefix length\n")
+DEFPY(
+ match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd,
+ "match ip next-hop prefix-len (0-32)$length",
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop IP address\n"
+ "Match prefixlen of given nexthop\n"
+ "Prefix length\n")
{
- return zebra_route_match_add(vty, "ip next-hop prefix-len",
- argv[4]->arg, RMAP_EVENT_MATCH_ADDED);
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-length']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:ipv4-prefix-length", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_ip_nexthop_prefix_len,
- no_match_ip_nexthop_prefix_len_cmd,
- "no match ip next-hop prefix-len [(0-32)]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match prefixlen of nexthop ip address\n"
- "Match prefix length of nexthop\n"
- "Prefix length\n")
-{
- char *plen = (argc == 6) ? argv[5]->arg : NULL;
- return zebra_route_match_delete(vty, "ip next-hop prefix-len", plen,
- RMAP_EVENT_MATCH_DELETED);
-}
-
-DEFUN (match_source_protocol,
- match_source_protocol_cmd,
- "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>",
- MATCH_STR
- "Match protocol via which the route was learnt\n"
- "BGP protocol\n"
- "OSPF protocol\n"
- "RIP protocol\n"
- "RIPNG protocol\n"
- "ISIS protocol\n"
- "OSPF6 protocol\n"
- "PIM protocol\n"
- "NHRP protocol\n"
- "EIGRP protocol\n"
- "BABEL protocol\n"
- "Routes from directly connected peer\n"
- "Routes from system configuration\n"
- "Routes from kernel\n"
- "Statically configured routes\n"
- "SHARP process\n")
-{
- char *proto = argv[2]->text;
- int i;
+DEFPY(
+ no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd,
+ "no match ip next-hop prefix-len [(0-32)]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match prefixlen of nexthop IP address\n"
+ "Match prefix length of nexthop\n"
+ "Prefix length\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-length']";
- i = proto_name2num(proto);
- if (i < 0) {
- vty_out(vty, "invalid protocol name \"%s\"\n", proto);
- return CMD_WARNING_CONFIG_FAILED;
- }
- return zebra_route_match_add(vty, "source-protocol", proto,
- RMAP_EVENT_MATCH_ADDED);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_match_source_protocol,
- no_match_source_protocol_cmd,
- "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>]",
- NO_STR
- MATCH_STR
- "No match protocol via which the route was learnt\n"
- "BGP protocol\n"
- "OSPF protocol\n"
- "RIP protocol\n"
- "RIPNG protocol\n"
- "ISIS protocol\n"
- "OSPF6 protocol\n"
- "PIM protocol\n"
- "NHRP protocol\n"
- "EIGRP protocol\n"
- "BABEL protocol\n"
- "Routes from directly connected peer\n"
- "Routes from system configuration\n"
- "Routes from kernel\n"
- "Statically configured routes\n"
- "SHARP process\n")
-{
- char *proto = (argc == 4) ? argv[3]->text : NULL;
- return zebra_route_match_delete(vty, "source-protocol", proto,
- RMAP_EVENT_MATCH_DELETED);
-}
-
-DEFUN (match_source_instance,
- match_source_instance_cmd,
- "match source-instance (0-255)",
- MATCH_STR
- "Match the protocol's instance number\n"
- "The instance number\n")
-{
- char *instance = argv[2]->arg;
-
- return zebra_route_match_add(vty, "source-instance", instance,
- RMAP_EVENT_MATCH_ADDED);
-}
-
-DEFUN (no_match_source_instance,
- no_match_source_instance_cmd,
- "no match source-instance [(0-255)]",
- NO_STR MATCH_STR
- "Match the protocol's instance number\n"
- "The instance number\n")
-{
- char *instance = (argc == 4) ? argv[3]->arg : NULL;
-
- return zebra_route_match_delete(vty, "source-instance", instance,
- RMAP_EVENT_MATCH_ADDED);
+DEFPY(
+ match_source_protocol, match_source_protocol_cmd,
+ "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto",
+ MATCH_STR
+ "Match protocol via which the route was learnt\n"
+ FRR_REDIST_HELP_STR_ZEBRA)
+{
+ const char *xpath = "./match-condition[condition='source-protocol']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-protocol", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-/* set functions */
+DEFPY(
+ no_match_source_protocol, no_match_source_protocol_cmd,
+ "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]",
+ NO_STR
+ MATCH_STR
+ "Match protocol via which the route was learnt\n"
+ FRR_REDIST_HELP_STR_ZEBRA)
+{
+ const char *xpath = "./match-condition[condition='source-protocol']";
-DEFUN (set_src,
- set_src_cmd,
- "set src <A.B.C.D|X:X::X:X>",
- SET_STR
- "src address for route\n"
- "IPv4 src address\n"
- "IPv6 src address\n")
-{
- int idx_ip = 2;
- union g_addr src;
- struct interface *pif = NULL;
- int family;
- struct prefix p;
- struct vrf *vrf;
-
- if (inet_pton(AF_INET, argv[idx_ip]->arg, &src.ipv4) != 1) {
- if (inet_pton(AF_INET6, argv[idx_ip]->arg, &src.ipv6) != 1) {
- vty_out(vty, "%% not a valid IPv4/v6 address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- p.family = family = AF_INET6;
- p.u.prefix6 = src.ipv6;
- p.prefixlen = IPV6_MAX_BITLEN;
- } else {
- p.family = family = AF_INET;
- p.u.prefix4 = src.ipv4;
- p.prefixlen = IPV4_MAX_BITLEN;
- }
+ return nb_cli_apply_changes(vty, NULL);
+}
- if (!zebra_check_addr(&p)) {
- vty_out(vty, "%% not a valid source IPv4/v6 address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+DEFPY(
+ match_source_instance, match_source_instance_cmd,
+ "match source-instance (0-255)$instance",
+ MATCH_STR
+ "Match the protocol's instance number\n"
+ "The instance number\n")
+{
+ const char *xpath = "./match-condition[condition='source-instance']";
+ char xpath_value[XPATH_MAXLEN];
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- if (family == AF_INET)
- pif = if_lookup_exact_address((void *)&src.ipv4,
- AF_INET, vrf->vrf_id);
- else if (family == AF_INET6)
- pif = if_lookup_exact_address((void *)&src.ipv6,
- AF_INET6, vrf->vrf_id);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-instance", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str);
- if (pif != NULL)
- break;
- }
+ return nb_cli_apply_changes(vty, NULL);
+}
- if (!pif) {
- vty_out(vty, "%% not a local address\n");
- return CMD_WARNING_CONFIG_FAILED;
+DEFPY(
+ no_match_source_instance, no_match_source_instance_cmd,
+ "no match source-instance [(0-255)]",
+ NO_STR MATCH_STR
+ "Match the protocol's instance number\n"
+ "The instance number\n")
+{
+ const char *xpath = "./match-condition[condition='source-instance']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+/* set functions */
+
+DEFPY(
+ set_src, set_src_cmd,
+ "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>",
+ SET_STR
+ "src address for route\n"
+ "IPv4 src address\n"
+ "IPv6 src address\n")
+{
+ const char *xpath = "./set-action[action='source']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (addrv4_str) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-v4", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ addrv4_str);
+ } else {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/frr-zebra:source-v6", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ addrv6_str);
}
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- return generic_set_add(vty, index, "src", argv[idx_ip]->arg);
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_set_src,
- no_set_src_cmd,
- "no set src [<A.B.C.D|X:X::X:X>]",
- NO_STR
- SET_STR
- "Source address for route\n"
- "IPv4 address\n"
- "IPv6 address\n")
-{
- char *ip = (argc == 4) ? argv[3]->arg : NULL;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- return generic_set_delete(vty, index, "src", ip);
+DEFPY(
+ no_set_src, no_set_src_cmd,
+ "no set src [<A.B.C.D|X:X::X:X>]",
+ NO_STR
+ SET_STR
+ "Source address for route\n"
+ "IPv4 address\n"
+ "IPv6 address\n")
+{
+ const char *xpath = "./set-action[action='source']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (zebra_route_map_timer,
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index a891ffb76a..ea2b6752b3 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -223,10 +223,11 @@ void zebra_router_terminate(void)
zebra_vxlan_disable();
zebra_mlag_terminate();
- hash_clean(zrouter.nhgs, zebra_nhg_hash_free);
- hash_free(zrouter.nhgs);
- hash_clean(zrouter.nhgs_id, NULL);
+ /* Free NHE in ID table only since it has unhashable entries as well */
+ hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free);
hash_free(zrouter.nhgs_id);
+ hash_clean(zrouter.nhgs, NULL);
+ hash_free(zrouter.nhgs);
hash_clean(zrouter.rules_hash, zebra_pbr_rules_free);
hash_free(zrouter.rules_hash);
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 59bd0e55f0..773e5a6415 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -218,6 +218,9 @@ extern void multicast_mode_ipv4_set(enum multicast_mode mode);
extern enum multicast_mode multicast_mode_ipv4_get(void);
+/* zebra_northbound.c */
+extern const struct frr_yang_module_info frr_zebra_info;
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
index 5de45c0294..89b8238c29 100644
--- a/zebra/zebra_snmp.c
+++ b/zebra/zebra_snmp.c
@@ -266,9 +266,9 @@ static void check_replace(struct route_node *np2, struct route_entry *re2,
return;
}
- if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0)
+ if (prefix_cmp(&(*np)->p, &np2->p) < 0)
return;
- if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0) {
+ if (prefix_cmp(&(*np)->p, &np2->p) > 0) {
*np = np2;
*re = re2;
return;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index dfa7d5ae92..ee1e251a69 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -178,7 +178,7 @@ static int zebra_vrf_disable(struct vrf *vrf)
zebra_vxlan_vrf_disable(zvrf);
#if defined(HAVE_RTADV)
- rtadv_terminate(zvrf);
+ rtadv_vrf_terminate(zvrf);
#endif
/* Inform clients that the VRF is now inactive. This is a
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 5448e17073..268ee12a65 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -193,7 +193,7 @@ struct zebra_vrf {
static inline vrf_id_t zvrf_id(struct zebra_vrf *zvrf)
{
if (!zvrf || !zvrf->vrf)
- return VRF_UNKNOWN;
+ return VRF_DEFAULT;
return zvrf->vrf->vrf_id;
}
@@ -206,6 +206,8 @@ static inline const char *zvrf_ns_name(struct zebra_vrf *zvrf)
static inline const char *zvrf_name(struct zebra_vrf *zvrf)
{
+ if (!zvrf || !zvrf->vrf)
+ return "Unknown";
return zvrf->vrf->name;
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index ccc6e9e46b..8024db4ca7 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -54,6 +54,7 @@
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_nhg.h"
#include "zebra/interface.h"
+#include "northbound_cli.h"
extern int allow_delete;
@@ -164,7 +165,8 @@ DEFUN (show_ip_rpf_addr,
return CMD_SUCCESS;
}
-static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
+static char re_status_output_char(const struct route_entry *re,
+ const struct nexthop *nhop)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
@@ -187,6 +189,152 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
return ' ';
}
+/*
+ * TODO -- Show backup nexthop info
+ */
+static void show_nh_backup_helper(struct vty *vty,
+ const struct nhg_hash_entry *nhe,
+ const struct nexthop *nexthop)
+{
+ /* Double-check that there _is_ a backup */
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return;
+
+ /* Locate the backup nexthop */
+
+ /* Format the backup (indented) */
+
+}
+
+/*
+ * Helper api to format output for a nexthop, used in the 'detailed'
+ * output path.
+ */
+static void show_nexthop_detail_helper(struct vty *vty,
+ const struct route_entry *re,
+ const struct nexthop *nexthop)
+{
+ char addrstr[32];
+ char buf[MPLS_LABEL_STRLEN];
+
+ vty_out(vty, " %c%s",
+ re_status_output_char(re, nexthop),
+ nexthop->rparent ? " " : "");
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, " %s",
+ inet_ntoa(nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, " %s",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+ buf, sizeof(buf)));
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, " directly connected, %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty,
+ " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((re->vrf_id != nexthop->vrf_id)
+ && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+ struct vrf *vrf =
+ vrf_lookup_by_id(nexthop->vrf_id);
+
+ if (vrf)
+ vty_out(vty, "(vrf %s)", vrf->name);
+ else
+ vty_out(vty, "(vrf UNKNOWN)");
+ }
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ vty_out(vty, " (duplicate nexthop removed)");
+
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out(vty, " inactive");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ vty_out(vty, " onlink");
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " (recursive)");
+
+ /* Source specified? */
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop->src.ipv4.s_addr) {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4,
+ addrstr, sizeof(addrstr)))
+ vty_out(vty, ", src %s",
+ addrstr);
+ }
+ break;
+
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
+ &in6addr_any)) {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6,
+ addrstr, sizeof(addrstr)))
+ vty_out(vty, ", src %s",
+ addrstr);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (re->nexthop_mtu)
+ vty_out(vty, ", mtu %u", re->nexthop_mtu);
+
+ /* Label information */
+ if (nexthop->nh_label && nexthop->nh_label->num_labels) {
+ vty_out(vty, ", label %s",
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label, buf,
+ sizeof(buf), 1 /*pretty*/));
+ }
+
+ if (nexthop->weight)
+ vty_out(vty, ", weight %u", nexthop->weight);
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast, bool use_fib, bool show_ng)
@@ -253,129 +401,122 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
- char addrstr[32];
-
- vty_out(vty, " %c%s",
- re_status_output_char(re, nexthop),
- nexthop->rparent ? " " : "");
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " %s",
- inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6,
- buf, sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " directly connected, %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty,
- " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
- }
-
- if ((re->vrf_id != nexthop->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- struct vrf *vrf =
- vrf_lookup_by_id(nexthop->vrf_id);
-
- if (vrf)
- vty_out(vty, "(vrf %s)", vrf->name);
- else
- vty_out(vty, "(vrf UNKNOWN)");
- }
+ /* Use helper to format each nexthop */
+ show_nexthop_detail_helper(vty, re, nexthop);
+ vty_out(vty, "\n");
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- vty_out(vty, " (duplicate nexthop removed)");
+ /* Include backup info, if present */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ show_nh_backup_helper(vty, re->nhe, nexthop);
+ }
+ vty_out(vty, "\n");
+ }
+}
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+/*
+ * Helper for nexthop output, used in the 'show ip route' path
+ */
+static void show_route_nexthop_helper(struct vty *vty,
+ const struct route_entry *re,
+ const struct nexthop *nexthop)
+{
+ char buf[MPLS_LABEL_STRLEN];
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, " via %s",
+ inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
+ sizeof(buf)));
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, " is directly connected, %s",
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, " unreachable");
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ vty_out(vty, " (ICMP unreachable)");
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ vty_out(vty, " (ICMP admin-prohibited)");
+ break;
+ case BLACKHOLE_NULL:
+ vty_out(vty, " (blackhole)");
+ break;
+ case BLACKHOLE_UNSPEC:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ if ((re == NULL || (nexthop->vrf_id != re->vrf_id)) &&
+ (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
+ struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET,
- &nexthop->src.ipv4,
- addrstr, sizeof(addrstr)))
- vty_out(vty, ", src %s",
- addrstr);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
- &in6addr_any)) {
- if (inet_ntop(AF_INET6,
- &nexthop->src.ipv6,
- addrstr, sizeof(addrstr)))
- vty_out(vty, ", src %s",
- addrstr);
- }
- break;
- default:
- break;
- }
+ if (vrf)
+ vty_out(vty, " (vrf %s)", vrf->name);
+ else
+ vty_out(vty, " (vrf UNKNOWN)");
+ }
- if (re->nexthop_mtu)
- vty_out(vty, ", mtu %u", re->nexthop_mtu);
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out(vty, " inactive");
- /* Label information */
- if (nexthop->nh_label
- && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(
- nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
- }
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ vty_out(vty, " onlink");
- if (nexthop->weight)
- vty_out(vty, ", weight %u", nexthop->weight);
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " (recursive)");
- vty_out(vty, "\n");
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop->src.ipv4.s_addr) {
+ if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
+ sizeof(buf)))
+ vty_out(vty, ", src %s", buf);
}
- vty_out(vty, "\n");
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
+ if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
+ sizeof(buf)))
+ vty_out(vty, ", src %s", buf);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Label information */
+ if (nexthop->nh_label && nexthop->nh_label->num_labels) {
+ vty_out(vty, ", label %s",
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label, buf,
+ sizeof(buf), 1));
}
+
+ if ((re == NULL) && nexthop->weight)
+ vty_out(vty, ", weight %u", nexthop->weight);
}
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
@@ -625,6 +766,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
json_labels);
}
+ if (nexthop->weight)
+ json_object_int_add(json_nexthop, "weight",
+ nexthop->weight);
+
json_object_array_add(json_nexthops, json_nexthop);
}
@@ -660,105 +805,46 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
len - 3 + (2 * nexthop_level(nexthop)), ' ');
}
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " via %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
+ show_route_nexthop_helper(vty, re, nexthop);
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is directly connected, %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty, " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
- }
-
- if ((nexthop->vrf_id != re->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
-
- if (vrf)
- vty_out(vty, "(vrf %s)", vrf->name);
- else
- vty_out(vty, "(vrf UNKNOWN)");
- }
+ if (nexthop->weight)
+ vty_out(vty, ", weight %u", nexthop->weight);
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+ vty_out(vty, ", %s\n", up_str);
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ /* Check for backup info */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ struct nexthop *backup;
+ int i;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ if (re->nhe->backup_info == NULL ||
+ re->nhe->backup_info->nhe == NULL)
+ continue;
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
- if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
+ i = 0;
+ for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg,
+ backup)) {
+ if (i == nexthop->backup_idx)
+ break;
+ i++;
}
- break;
- default:
- break;
- }
- /* Label information */
- if (nexthop->nh_label && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ /* Print useful backup info */
+ if (backup) {
+ /* TODO -- install state is not accurate */
+ vty_out(vty, " %*c [backup %d]",
+ /*re_status_output_char(re, backup),*/
+ len - 3 + (2 * nexthop_level(nexthop)),
+ ' ', nexthop->backup_idx);
+ show_route_nexthop_helper(vty, re, backup);
+ vty_out(vty, "\n");
+ }
}
-
- vty_out(vty, ", %s\n", up_str);
}
}
static void vty_show_ip_route_detail_json(struct vty *vty,
- struct route_node *rn, bool use_fib)
+ struct route_node *rn, bool use_fib)
{
json_object *json = NULL;
json_object *json_prefix = NULL;
@@ -1028,9 +1114,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
{
struct nexthop *nexthop = NULL;
struct nhg_connected *rb_node_dep = NULL;
- char buf[SRCDEST2STR_BUFFER];
-
struct vrf *nhe_vrf = vrf_lookup_by_id(nhe->vrf_id);
+ struct nexthop_group *backup_nhg;
vty_out(vty, "ID: %u\n", nhe->id);
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
@@ -1062,6 +1147,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
vty_out(vty, "\n");
}
+ /* Output nexthops */
for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
vty_out(vty, " ");
@@ -1069,100 +1155,56 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
/* Make recursive nexthops a bit more clear */
vty_out(vty, " ");
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " %s", inet_ntoa(nexthop->gate.ipv4));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
+ show_route_nexthop_helper(vty, NULL, nexthop);
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " directly connected %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- vty_out(vty, " (ICMP unreachable)");
- break;
- case BLACKHOLE_ADMINPROHIB:
- vty_out(vty, " (ICMP admin-prohibited)");
- break;
- case BLACKHOLE_NULL:
- vty_out(vty, " (blackhole)");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- default:
- break;
+ if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_HAS_BACKUP))
+ vty_out(vty, " [backup %d]",
+ nexthop->backup_idx);
+
+ vty_out(vty, "\n");
+ continue;
}
- struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+ /* TODO -- print more useful backup info */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ struct nexthop *backup;
+ int i;
- if (vrf)
- vty_out(vty, " (vrf %s)", vrf->name);
- else
- vty_out(vty, " (vrf UNKNOWN)");
+ i = 0;
+ for (ALL_NEXTHOPS(nhe->backup_info->nhe->nhg, backup)) {
+ if (i == nexthop->backup_idx)
+ break;
+ i++;
+ }
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- vty_out(vty, " inactive");
+ /* TODO */
+ if (backup)
+ vty_out(vty, " [backup %d]",
+ nexthop->backup_idx);
+ else
+ vty_out(vty, " [backup INVALID]");
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- vty_out(vty, " onlink");
+ vty_out(vty, "\n");
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " (recursive)");
+ /* Output backup nexthops (if any) */
+ backup_nhg = zebra_nhg_get_backup_nhg(nhe);
+ if (backup_nhg) {
+ vty_out(vty, " Backups:\n");
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
- if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- default:
- break;
- }
+ for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ vty_out(vty, " ");
+ else
+ /* Make recursive nexthops a bit more clear */
+ vty_out(vty, " ");
- /* Label information */
- if (nexthop->nh_label && nexthop->nh_label->num_labels) {
- vty_out(vty, ", label %s",
- mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ show_route_nexthop_helper(vty, NULL, nexthop);
+ vty_out(vty, "\n");
}
-
- if (nexthop->weight)
- vty_out(vty, ", weight %u", nexthop->weight);
-
- vty_out(vty, "\n");
}
if (!zebra_nhg_dependents_is_empty(nhe)) {
@@ -2893,17 +2935,29 @@ DEFPY (clear_evpn_dup_addr,
"IPv4 address\n"
"IPv6 address\n")
{
- struct zebra_vrf *zvrf;
struct ipaddr host_ip = {.ipa_type = IPADDR_NONE };
int ret = CMD_SUCCESS;
+ struct list *input;
+ struct yang_data *yang_dup = NULL, *yang_dup_ip = NULL,
+ *yang_dup_mac = NULL;
- zvrf = zebra_vrf_get_evpn();
- if (vni_str) {
+ input = list_new();
+
+ if (!vni_str) {
+ yang_dup = yang_data_new(
+ "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice",
+ "all-case");
+ } else {
+ yang_dup = yang_data_new_uint32(
+ "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id",
+ vni);
if (!is_zero_mac(&mac->eth_addr)) {
- ret = zebra_vxlan_clear_dup_detect_vni_mac(vty, zvrf,
- vni,
- &mac->eth_addr);
- } else if (ip) {
+ yang_dup_mac = yang_data_new_mac(
+ "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/mac-addr",
+ &mac->eth_addr);
+ if (yang_dup_mac)
+ listnode_add(input, yang_dup_mac);
+ } else if (ip) {
if (sockunion_family(ip) == AF_INET) {
host_ip.ipa_type = IPADDR_V4;
host_ip.ipaddr_v4.s_addr = sockunion2ip(ip);
@@ -2912,16 +2966,23 @@ DEFPY (clear_evpn_dup_addr,
memcpy(&host_ip.ipaddr_v6, &ip->sin6.sin6_addr,
sizeof(struct in6_addr));
}
- ret = zebra_vxlan_clear_dup_detect_vni_ip(vty, zvrf,
- vni,
- &host_ip);
- } else
- ret = zebra_vxlan_clear_dup_detect_vni(vty, zvrf, vni);
- } else {
- ret = zebra_vxlan_clear_dup_detect_vni_all(vty, zvrf);
+ yang_dup_ip = yang_data_new_ip(
+ "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/vni-ipaddr",
+ &host_ip);
+
+ if (yang_dup_ip)
+ listnode_add(input, yang_dup_ip);
+ }
}
+ if (yang_dup) {
+ listnode_add(input, yang_dup);
+ ret = nb_cli_rpc("/frr-zebra:clear-evpn-dup-addr", input, NULL);
+ }
+
+ list_delete(&input);
+
return ret;
}
@@ -3437,22 +3498,42 @@ DEFUN_HIDDEN (show_frr,
}
/* IP node for static routes. */
-static struct cmd_node ip_node = {IP_NODE, "", 1};
-static struct cmd_node protocol_node = {PROTOCOL_NODE, "", 1};
+static int zebra_ip_config(struct vty *vty);
+static struct cmd_node ip_node = {
+ .name = "static ip",
+ .node = IP_NODE,
+ .prompt = "",
+ .config_write = zebra_ip_config,
+};
+static int config_write_protocol(struct vty *vty);
+static struct cmd_node protocol_node = {
+ .name = "protocol",
+ .node = PROTOCOL_NODE,
+ .prompt = "",
+ .config_write = config_write_protocol,
+};
/* table node for routing tables. */
-static struct cmd_node table_node = {TABLE_NODE,
- "", /* This node has no interface. */
- 1};
-static struct cmd_node forwarding_node = {FORWARDING_NODE,
- "", /* This node has no interface. */
- 1};
+static int config_write_table(struct vty *vty);
+static struct cmd_node table_node = {
+ .name = "table",
+ .node = TABLE_NODE,
+ .prompt = "",
+ .config_write = config_write_table,
+};
+static int config_write_forwarding(struct vty *vty);
+static struct cmd_node forwarding_node = {
+ .name = "forwarding",
+ .node = FORWARDING_NODE,
+ .prompt = "",
+ .config_write = config_write_forwarding,
+};
/* Route VTY. */
void zebra_vty_init(void)
{
/* Install configuration write function. */
- install_node(&table_node, config_write_table);
- install_node(&forwarding_node, config_write_forwarding);
+ install_node(&table_node);
+ install_node(&forwarding_node);
install_element(VIEW_NODE, &show_ip_forwarding_cmd);
install_element(CONFIG_NODE, &ip_forwarding_cmd);
@@ -3466,8 +3547,8 @@ void zebra_vty_init(void)
/* Route-map */
zebra_route_map_init();
- install_node(&ip_node, zebra_ip_config);
- install_node(&protocol_node, config_write_protocol);
+ install_node(&ip_node);
+ install_node(&protocol_node);
install_element(CONFIG_NODE, &allow_external_route_update_cmd);
install_element(CONFIG_NODE, &no_allow_external_route_update_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 2e1daa6fdf..d23cdfccd8 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -121,11 +121,11 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if,
/* l3-vni next-hop neigh related APIs */
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
- struct ipaddr *ip);
+ const struct ipaddr *ip);
static void *zl3vni_nh_alloc(void *p);
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
- struct ipaddr *vtep_ip,
- struct ethaddr *rmac);
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac);
static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
@@ -133,10 +133,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
/* l3-vni rmac related APIs */
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac);
+ const struct ethaddr *rmac);
static void *zl3vni_rmac_alloc(void *p);
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac);
+ const struct ethaddr *rmac);
static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
@@ -1515,8 +1515,8 @@ static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt)
struct mac_walk_ctx *wctx = ctxt;
char vni_str[VNI_STR_LEN];
- vty = (struct vty *)wctx->vty;
- json = (struct json_object *)wctx->json;
+ vty = wctx->vty;
+ json = wctx->json;
zvni = (zebra_vni_t *)bucket->data;
wctx->zvni = zvni;
@@ -1586,8 +1586,8 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket,
struct mac_walk_ctx *wctx = ctxt;
char vni_str[VNI_STR_LEN];
- vty = (struct vty *)wctx->vty;
- json = (struct json_object *)wctx->json;
+ vty = wctx->vty;
+ json = wctx->json;
zvni = (zebra_vni_t *)bucket->data;
if (!zvni) {
@@ -3691,7 +3691,7 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|| zif->link != br_if)
continue;
- vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
+ vl = &zif->l2info.vl;
if (vl->vid == vid) {
found = 1;
@@ -4434,7 +4434,7 @@ static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args)
}
static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
- struct prefix *host)
+ const struct prefix *host)
{
struct host_rb_entry lookup;
struct host_rb_entry *hle;
@@ -4473,7 +4473,7 @@ static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
* Look up MAC hash entry.
*/
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
- struct ethaddr *rmac)
+ const struct ethaddr *rmac)
{
zebra_mac_t tmp;
zebra_mac_t *pmac;
@@ -4502,7 +4502,8 @@ static void *zl3vni_rmac_alloc(void *p)
/*
* Add RMAC entry to l3-vni
*/
-static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
+static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+ const struct ethaddr *rmac)
{
zebra_mac_t tmp_rmac;
zebra_mac_t *zrmac = NULL;
@@ -4632,9 +4633,10 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
}
/* handle rmac add */
-static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
+static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni,
+ const struct ethaddr *rmac,
+ const struct ipaddr *vtep_ip,
+ const struct prefix *host_prefix)
{
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
@@ -4709,7 +4711,8 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
/*
* Look up nh hash entry on a l3-vni.
*/
-static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip)
+static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *ip)
{
zebra_neigh_t tmp;
zebra_neigh_t *n;
@@ -4739,8 +4742,9 @@ static void *zl3vni_nh_alloc(void *p)
/*
* Add neighbor entry.
*/
-static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
- struct ethaddr *mac)
+static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
{
zebra_neigh_t tmp_n;
zebra_neigh_t *n = NULL;
@@ -4822,9 +4826,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
}
/* add remote vtep as a neigh entry */
-static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
- struct ethaddr *rmac,
- struct prefix *host_prefix)
+static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni,
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac,
+ const struct prefix *host_prefix)
{
char buf[ETHER_ADDR_STRLEN];
char buf1[ETHER_ADDR_STRLEN];
@@ -5960,9 +5965,9 @@ int is_l3vni_for_prefix_routes_only(vni_t vni)
}
/* handle evpn route in vrf table */
-void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
- struct ipaddr *vtep_ip,
- struct prefix *host_prefix)
+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)
{
zebra_l3vni_t *zl3vni = NULL;
struct ipaddr ipv4_vtep;
@@ -6848,9 +6853,8 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
}
-int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
- struct zebra_vrf *zvrf,
- vni_t vni, struct ethaddr *macaddr)
+int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
+ struct ethaddr *macaddr)
{
zebra_vni_t *zvni;
zebra_mac_t *mac;
@@ -6858,24 +6862,23 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
zebra_neigh_t *nbr = NULL;
if (!is_evpn_enabled())
- return CMD_SUCCESS;
+ return 0;
zvni = zvni_lookup(vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
- return CMD_WARNING;
+ zlog_warn("VNI %u does not exist\n", vni);
+ return -1;
}
mac = zvni_mac_lookup(zvni, macaddr);
if (!mac) {
- vty_out(vty, "%% Requested MAC does not exist in VNI %u\n",
- vni);
- return CMD_WARNING;
+ zlog_warn("Requested MAC does not exist in VNI %u\n", vni);
+ return -1;
}
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- vty_out(vty, "%% Requested MAC is not duplicate detected\n");
- return CMD_WARNING;
+ zlog_warn("Requested MAC is not duplicate detected\n");
+ return -1;
}
/* Remove all IPs as duplicate associcated with this MAC */
@@ -6910,7 +6913,7 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
/* warn-only action return */
if (!zvrf->dad_freeze)
- return CMD_SUCCESS;
+ return 0;
/* Local: Notify Peer VTEPs, Remote: Install the entry */
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
@@ -6919,7 +6922,7 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
&mac->macaddr,
mac->flags,
mac->loc_seq))
- return CMD_SUCCESS;
+ return 0;
/* Process all neighbors associated with this MAC. */
zvni_process_neigh_on_local_mac_change(zvni, mac, 0);
@@ -6931,12 +6934,11 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
zvni_mac_install(zvni, mac);
}
- return CMD_SUCCESS;
+ return 0;
}
-int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
- struct zebra_vrf *zvrf,
- vni_t vni, struct ipaddr *ip)
+int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
+ struct ipaddr *ip)
{
zebra_vni_t *zvni;
zebra_neigh_t *nbr;
@@ -6945,38 +6947,35 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
char buf2[ETHER_ADDR_STRLEN];
if (!is_evpn_enabled())
- return CMD_SUCCESS;
+ return 0;
zvni = zvni_lookup(vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
- return CMD_WARNING;
+ zlog_debug("VNI %u does not exist\n", vni);
+ return -1;
}
nbr = zvni_neigh_lookup(zvni, ip);
if (!nbr) {
- vty_out(vty,
- "%% Requested host IP does not exist in VNI %u\n",
- vni);
- return CMD_WARNING;
+ zlog_warn("Requested host IP does not exist in VNI %u\n", vni);
+ return -1;
}
ipaddr2str(&nbr->ip, buf, sizeof(buf));
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
- vty_out(vty,
- "%% Requested host IP %s is not duplicate detected\n",
- buf);
- return CMD_WARNING;
+ zlog_warn("Requested host IP %s is not duplicate detected\n",
+ buf);
+ return -1;
}
mac = zvni_mac_lookup(zvni, &nbr->emac);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- vty_out(vty,
- "%% Requested IP's associated MAC %s is still in duplicate state\n",
+ zlog_warn(
+ "Requested IP's associated MAC %s is still in duplicate state\n",
prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)));
- return CMD_WARNING_CONFIG_FAILED;
+ return -1;
}
if (IS_ZEBRA_DEBUG_VXLAN)
@@ -6998,7 +6997,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
zvni_neigh_install(zvni, nbr);
}
- return CMD_SUCCESS;
+ return 0;
}
static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
@@ -7097,7 +7096,6 @@ static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt)
static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
void **args)
{
- struct vty *vty;
zebra_vni_t *zvni;
struct zebra_vrf *zvrf;
struct mac_walk_ctx m_wctx;
@@ -7107,12 +7105,10 @@ static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
if (!zvni)
return;
- vty = (struct vty *)args[0];
- zvrf = (struct zebra_vrf *)args[1];
+ zvrf = (struct zebra_vrf *)args[0];
if (hashcount(zvni->neigh_table)) {
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.vty = vty;
n_wctx.zvni = zvni;
n_wctx.zvrf = zvrf;
hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
@@ -7122,51 +7118,45 @@ static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
if (num_valid_macs(zvni)) {
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
m_wctx.zvni = zvni;
- m_wctx.vty = vty;
m_wctx.zvrf = zvrf;
hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
}
}
-int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty,
- struct zebra_vrf *zvrf)
+int zebra_vxlan_clear_dup_detect_vni_all(struct zebra_vrf *zvrf)
{
- void *args[2];
+ void *args[1];
if (!is_evpn_enabled())
- return CMD_SUCCESS;
+ return 0;
- args[0] = vty;
- args[1] = zvrf;
+ args[0] = zvrf;
hash_iterate(zvrf->vni_table,
(void (*)(struct hash_bucket *, void *))
zvni_clear_dup_detect_hash_vni_all, args);
- return CMD_SUCCESS;
+ return 0;
}
-int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
- struct zebra_vrf *zvrf,
- vni_t vni)
+int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni)
{
zebra_vni_t *zvni;
struct mac_walk_ctx m_wctx;
struct neigh_walk_ctx n_wctx;
if (!is_evpn_enabled())
- return CMD_SUCCESS;
+ return 0;
zvni = zvni_lookup(vni);
if (!zvni) {
- vty_out(vty, "%% VNI %u does not exist\n", vni);
- return CMD_WARNING;
+ zlog_warn("VNI %u does not exist\n", vni);
+ return -1;
}
if (hashcount(zvni->neigh_table)) {
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.vty = vty;
n_wctx.zvni = zvni;
n_wctx.zvrf = zvrf;
hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
@@ -7176,12 +7166,11 @@ int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
if (num_valid_macs(zvni)) {
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
m_wctx.zvni = zvni;
- m_wctx.vty = vty;
m_wctx.zvrf = zvrf;
hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
}
- return CMD_SUCCESS;
+ return 0;
}
/*
@@ -7412,7 +7401,7 @@ void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS)
* clear all duplicate detected addresses.
*/
if (zvrf->dup_addr_detect && !dup_addr_detect)
- zebra_vxlan_clear_dup_detect_vni_all(NULL, zvrf);
+ zebra_vxlan_clear_dup_detect_vni_all(zvrf);
zvrf->dup_addr_detect = dup_addr_detect;
zvrf->dad_time = time;
@@ -10254,7 +10243,7 @@ static int zebra_evpn_pim_cfg_clean_up(struct zserv *client)
{
struct zebra_vrf *zvrf = zebra_vrf_get_evpn();
- if (CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) {
+ if (zvrf && CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("VxLAN SG updates to PIM, stop");
UNSET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 6ca93f6cb6..064dda6cd0 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -199,24 +199,19 @@ extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
extern void zebra_vxlan_init(void);
extern void zebra_vxlan_disable(void);
extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
- struct ethaddr *rmac,
- struct ipaddr *ip,
- struct prefix *host_prefix);
+ const struct ethaddr *rmac,
+ const struct ipaddr *ip,
+ const struct prefix *host_prefix);
extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
struct ipaddr *vtep_ip,
struct prefix *host_prefix);
-extern int zebra_vxlan_clear_dup_detect_vni_mac(struct vty *vty,
- struct zebra_vrf *zvrf,
+extern int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf,
vni_t vni,
struct ethaddr *macaddr);
-extern int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
- struct zebra_vrf *zvrf,
+extern int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf,
vni_t vni, struct ipaddr *ip);
-extern int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty,
- struct zebra_vrf *zvrf);
-extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
- struct zebra_vrf *zvrf,
- vni_t vni);
+extern int zebra_vxlan_clear_dup_detect_vni_all(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni);
extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx);
extern void zebra_evpn_init(void);
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index 100bb0e093..0a46fb2075 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -301,6 +301,7 @@ struct zebra_mac_t_ {
/* remote VTEP advertised MAC as default GW */
#define ZEBRA_MAC_REMOTE_DEF_GW 0x40
#define ZEBRA_MAC_DUPLICATE 0x80
+#define ZEBRA_MAC_FPM_SENT 0x100 /* whether or not this entry was sent. */
/* back pointer to zvni */
zebra_vni_t *zvni;
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 7f806d82c3..8a1ed115a7 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -888,7 +888,9 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
vty_out(vty, "Client: %s", zebra_route_string(client->proto));
if (client->instance)
- vty_out(vty, " Instance: %d", client->instance);
+ vty_out(vty, " Instance: %u", client->instance);
+ if (client->session_id)
+ vty_out(vty, " [%u]", client->session_id);
vty_out(vty, "\n");
vty_out(vty, "------------------------ \n");
@@ -936,32 +938,32 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
vty_out(vty, "Type Add Update Del \n");
vty_out(vty, "================================================== \n");
- vty_out(vty, "IPv4 %-12d%-12d%-12d\n", client->v4_route_add_cnt,
+ vty_out(vty, "IPv4 %-12u%-12u%-12u\n", client->v4_route_add_cnt,
client->v4_route_upd8_cnt, client->v4_route_del_cnt);
- vty_out(vty, "IPv6 %-12d%-12d%-12d\n", client->v6_route_add_cnt,
+ vty_out(vty, "IPv6 %-12u%-12u%-12u\n", client->v6_route_add_cnt,
client->v6_route_upd8_cnt, client->v6_route_del_cnt);
- vty_out(vty, "Redist:v4 %-12d%-12d%-12d\n", client->redist_v4_add_cnt,
+ vty_out(vty, "Redist:v4 %-12u%-12u%-12u\n", client->redist_v4_add_cnt,
0, client->redist_v4_del_cnt);
- vty_out(vty, "Redist:v6 %-12d%-12d%-12d\n", client->redist_v6_add_cnt,
+ vty_out(vty, "Redist:v6 %-12u%-12u%-12u\n", client->redist_v6_add_cnt,
0, client->redist_v6_del_cnt);
- vty_out(vty, "Connected %-12d%-12d%-12d\n", client->ifadd_cnt, 0,
+ vty_out(vty, "Connected %-12u%-12u%-12u\n", client->ifadd_cnt, 0,
client->ifdel_cnt);
- vty_out(vty, "BFD peer %-12d%-12d%-12d\n", client->bfd_peer_add_cnt,
+ vty_out(vty, "BFD peer %-12u%-12u%-12u\n", client->bfd_peer_add_cnt,
client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
- vty_out(vty, "NHT v4 %-12d%-12d%-12d\n",
+ vty_out(vty, "NHT v4 %-12u%-12u%-12u\n",
client->v4_nh_watch_add_cnt, 0, client->v4_nh_watch_rem_cnt);
- vty_out(vty, "NHT v6 %-12d%-12d%-12d\n",
+ vty_out(vty, "NHT v6 %-12u%-12u%-12u\n",
client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
- vty_out(vty, "VxLAN SG %-12d%-12d%-12d\n", client->vxlan_sg_add_cnt,
+ vty_out(vty, "VxLAN SG %-12u%-12u%-12u\n", client->vxlan_sg_add_cnt,
0, client->vxlan_sg_del_cnt);
- vty_out(vty, "Interface Up Notifications: %d\n", client->ifup_cnt);
- vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt);
- vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt);
- vty_out(vty, "VNI delete notifications: %d\n", client->vnidel_cnt);
- vty_out(vty, "L3-VNI add notifications: %d\n", client->l3vniadd_cnt);
- vty_out(vty, "L3-VNI delete notifications: %d\n", client->l3vnidel_cnt);
- vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
- vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
+ vty_out(vty, "Interface Up Notifications: %u\n", client->ifup_cnt);
+ vty_out(vty, "Interface Down Notifications: %u\n", client->ifdown_cnt);
+ vty_out(vty, "VNI add notifications: %u\n", client->vniadd_cnt);
+ vty_out(vty, "VNI delete notifications: %u\n", client->vnidel_cnt);
+ vty_out(vty, "L3-VNI add notifications: %u\n", client->l3vniadd_cnt);
+ vty_out(vty, "L3-VNI delete notifications: %u\n", client->l3vnidel_cnt);
+ vty_out(vty, "MAC-IP add notifications: %u\n", client->macipadd_cnt);
+ vty_out(vty, "MAC-IP delete notifications: %u\n", client->macipdel_cnt);
TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
@@ -995,11 +997,16 @@ static void zebra_show_stale_client_detail(struct vty *vty,
time_t uptime;
struct client_gr_info *info = NULL;
struct zserv *s = NULL;
-
- if (client->instance)
- vty_out(vty, " Instance: %d", client->instance);
+ bool first_p = true;
TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ if (first_p) {
+ if (client->instance)
+ vty_out(vty, " Instance: %u", client->instance);
+ if (client->session_id)
+ vty_out(vty, " [%u]", client->session_id);
+ first_p = false;
+ }
vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
vty_out(vty, "Capabilities : ");
switch (info->capabilities) {
@@ -1070,19 +1077,26 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
client->v6_route_del_cnt);
}
-struct zserv *zserv_find_client(uint8_t proto, unsigned short instance)
+struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance,
+ uint32_t session_id)
{
struct listnode *node, *nnode;
struct zserv *client;
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
- if (client->proto == proto && client->instance == instance)
+ if (client->proto == proto && client->instance == instance &&
+ client->session_id == session_id)
return client;
}
return NULL;
}
+struct zserv *zserv_find_client(uint8_t proto, unsigned short instance)
+{
+ return zserv_find_client_session(proto, instance, 0);
+}
+
/* This command is for debugging purpose. */
DEFUN (show_zebra_client,
show_zebra_client_cmd,
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 08df664d56..5506c4299d 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -134,9 +134,10 @@ struct zserv {
/* Indicates if client is synchronous. */
bool synchronous;
- /* client's protocol */
+ /* client's protocol and session info */
uint8_t proto;
uint16_t instance;
+ uint32_t session_id;
/*
* Interested for MLAG Updates, and also stores the client
@@ -287,6 +288,24 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg);
extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
/*
+ * Retrieve a client by its protocol, instance number, and session id.
+ *
+ * proto
+ * protocol number
+ *
+ * instance
+ * instance number
+ *
+ * session_id
+ * session id
+ *
+ * Returns:
+ * The Zebra API client.
+ */
+struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance,
+ uint32_t session_id);
+
+/*
* Close a client.
*
* Kills a client's thread, removes the client from the client list and cleans