summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agg_table.h16
-rw-r--r--lib/command_match.c2
-rw-r--r--lib/compiler.h9
-rw-r--r--lib/frrlua.c2
-rw-r--r--lib/frrlua.h2
-rw-r--r--lib/grammar_sandbox_main.c4
-rw-r--r--lib/if.c54
-rw-r--r--lib/if.h81
-rw-r--r--lib/ipaddr.h2
-rw-r--r--lib/lib_vty.c2
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/libfrr.h3
-rw-r--r--lib/log.c88
-rw-r--r--lib/log.h2
-rw-r--r--lib/md5.c4
-rw-r--r--lib/memory.h3
-rw-r--r--lib/mlag.c5
-rw-r--r--lib/monotime.h20
-rw-r--r--lib/mpls.c2
-rw-r--r--lib/mpls.h5
-rw-r--r--lib/nexthop.c50
-rw-r--r--lib/nexthop.h26
-rw-r--r--lib/nexthop_group.c196
-rw-r--r--lib/nexthop_group.h9
-rw-r--r--lib/northbound.c7
-rw-r--r--lib/northbound.h11
-rw-r--r--lib/northbound_grpc.cpp21
-rw-r--r--lib/ntop.c2
-rw-r--r--lib/plist.c2
-rw-r--r--lib/prefix.h18
-rw-r--r--lib/printfrr.h14
-rw-r--r--lib/routemap_cli.c38
-rw-r--r--lib/routemap_northbound.c25
-rw-r--r--lib/skiplist.c15
-rw-r--r--lib/skiplist.h13
-rw-r--r--lib/smux.h2
-rw-r--r--lib/snmp.c4
-rw-r--r--lib/spf_backoff.c2
-rw-r--r--lib/spf_backoff.h2
-rw-r--r--lib/srcdest_table.c2
-rw-r--r--lib/srcdest_table.h2
-rw-r--r--lib/stream.c23
-rw-r--r--lib/stream.h25
-rw-r--r--lib/table.c2
-rw-r--r--lib/table.h4
-rw-r--r--lib/thread.c9
-rw-r--r--lib/vrf.c23
-rw-r--r--lib/vrf.h15
-rw-r--r--lib/vty.c9
-rw-r--r--lib/yang.c11
-rw-r--r--lib/yang.h10
-rw-r--r--lib/yang_translator.c4
-rw-r--r--lib/yang_wrappers.c5
-rw-r--r--lib/zclient.c360
-rw-r--r--lib/zclient.h37
55 files changed, 952 insertions, 354 deletions
diff --git a/lib/agg_table.h b/lib/agg_table.h
index 40ffe8c755..e98476f1b7 100644
--- a/lib/agg_table.h
+++ b/lib/agg_table.h
@@ -86,13 +86,13 @@ static inline struct agg_node *agg_route_next(struct agg_node *node)
}
static inline struct agg_node *agg_node_get(struct agg_table *table,
- struct prefix *p)
+ const struct prefix *p)
{
return agg_node_from_rnode(route_node_get(table->route_table, p));
}
static inline struct agg_node *
-agg_node_lookup(const struct agg_table *const table, struct prefix *p)
+agg_node_lookup(const struct agg_table *const table, const struct prefix *p)
{
return agg_node_from_rnode(route_node_lookup(table->route_table, p));
}
@@ -109,7 +109,7 @@ static inline struct agg_node *agg_route_next_until(struct agg_node *node,
}
static inline struct agg_node *agg_node_match(struct agg_table *table,
- struct prefix *p)
+ const struct prefix *p)
{
return agg_node_from_rnode(route_node_match(table->route_table, p));
}
@@ -155,6 +155,16 @@ static inline struct agg_table *agg_get_table(struct agg_node *node)
return (struct agg_table *)route_table_get_info(node->table);
}
+static inline const struct prefix *
+agg_node_get_prefix(const struct agg_node *node)
+{
+ return &node->p;
+}
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pRN" (struct agg_node *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/command_match.c b/lib/command_match.c
index 0195aebc17..801b05f157 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -88,7 +88,7 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
// prepend a dummy token to match that pesky start node
vector vvline = vector_init(vline->alloced + 1);
- vector_set_index(vvline, 0, (void *)XSTRDUP(MTYPE_TMP, "dummy"));
+ vector_set_index(vvline, 0, XSTRDUP(MTYPE_TMP, "dummy"));
memcpy(vvline->index + 1, vline->index,
sizeof(void *) * vline->alloced);
vvline->active = vline->active + 1;
diff --git a/lib/compiler.h b/lib/compiler.h
index e430925e69..217a60d888 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -305,7 +305,14 @@ extern "C" {
#include <inttypes.h>
#ifdef _FRR_ATTRIBUTE_PRINTFRR
-#define PRINTFRR(a, b) __attribute__((printfrr(a, b)))
+#define PRINTFRR(a, b) __attribute__((frr_format("frr_printf", a, b)))
+
+#undef PRIu64
+#undef PRId64
+#undef PRIx64
+#define PRIu64 "Lu"
+#define PRId64 "Ld"
+#define PRIx64 "Lx"
#else /* !_FRR_ATTRIBUTE_PRINTFRR */
#define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
diff --git a/lib/frrlua.c b/lib/frrlua.c
index 26610556dc..9f9cf8c1f6 100644
--- a/lib/frrlua.c
+++ b/lib/frrlua.c
@@ -5,7 +5,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
- * 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 Free Software
diff --git a/lib/frrlua.h b/lib/frrlua.h
index 374eb70311..40c7a67b89 100644
--- a/lib/frrlua.h
+++ b/lib/frrlua.h
@@ -5,7 +5,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Donald Sharp
*
- * 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 Free Software
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index 4bd8f5138a..aa54720dab 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -7,7 +7,7 @@
* Copyright (C) 2016 Cumulus Networks, Inc.
* Copyright (C) 2017 David Lamparter for NetDEF, 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 Free Software
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
vty_init(master, true);
lib_cmd_init();
- yang_init();
+ yang_init(true);
nb_init(master, NULL, 0);
vty_stdio(vty_do_exit);
diff --git a/lib/if.c b/lib/if.c
index dabf66799d..cc964106d0 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -582,23 +582,39 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
return NULL;
}
-void if_set_index(struct interface *ifp, ifindex_t ifindex)
+int if_set_index(struct interface *ifp, ifindex_t ifindex)
{
struct vrf *vrf;
+ if (ifp->ifindex == ifindex)
+ return 0;
+
vrf = vrf_get(ifp->vrf_id, NULL);
assert(vrf);
- if (ifp->ifindex == ifindex)
- return;
+ /*
+ * If there is already an interface with this ifindex, we will collide
+ * on insertion, so don't even try.
+ */
+ if (if_lookup_by_ifindex(ifindex, ifp->vrf_id))
+ return -1;
if (ifp->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_REMOVE(vrf, ifp);
ifp->ifindex = ifindex;
- if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_INSERT(vrf, ifp)
+ if (ifp->ifindex != IFINDEX_INTERNAL) {
+ /*
+ * This should never happen, since we checked if there was
+ * already an interface with the desired ifindex at the top of
+ * the function. Nevertheless.
+ */
+ if (IFINDEX_RB_INSERT(vrf, ifp))
+ return -1;
+ }
+
+ return 0;
}
void if_set_name(struct interface *ifp, const char *name)
@@ -1249,8 +1265,6 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
struct if_link_params *iflp =
XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params));
- if (iflp == NULL)
- return NULL;
/* Set TE metric equal to standard metric */
iflp->te_metric = ifp->metric;
@@ -1278,8 +1292,6 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
void if_link_params_free(struct interface *ifp)
{
- if (ifp->link_params == NULL)
- return;
XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
}
@@ -1657,31 +1669,7 @@ static int lib_interface_description_destroy(enum nb_event event,
/* clang-format off */
-#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
-/* gcc versions before 5.x miscalculate the size for structs with variable
- * length arrays (they just count it as size 0)
- */
-struct frr_yang_module_info_size3 {
- /* YANG module name. */
- const char *name;
-
- /* Northbound callbacks. */
- const struct {
- /* Data path of this YANG node. */
- const char *xpath;
-
- /* Callbacks implemented for this node. */
- struct nb_callbacks cbs;
-
- /* Priority - lower priorities are processed first. */
- uint32_t priority;
- } nodes[3];
-};
-
-const struct frr_yang_module_info_size3 frr_interface_info_size3 asm("frr_interface_info") = {
-#else
const struct frr_yang_module_info frr_interface_info = {
-#endif
.name = "frr-interface",
.nodes = {
{
diff --git a/lib/if.h b/lib/if.h
index 4ca2e79572..ac8d8e70ba 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -308,33 +308,58 @@ RB_HEAD(if_index_head, interface);
RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func)
DECLARE_QOBJ_TYPE(interface)
-#define IFNAME_RB_INSERT(vrf, ifp) \
- if (RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp))) \
- flog_err(EC_LIB_INTERFACE, \
- "%s(%s): corruption detected -- interface with this " \
- "name exists already in VRF %u!", \
- __func__, (ifp)->name, (ifp)->vrf_id);
-
-#define IFNAME_RB_REMOVE(vrf, ifp) \
- if (RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)) == NULL) \
- flog_err(EC_LIB_INTERFACE, \
- "%s(%s): corruption detected -- interface with this " \
- "name doesn't exist in VRF %u!", \
- __func__, (ifp)->name, (ifp)->vrf_id);
-
-#define IFINDEX_RB_INSERT(vrf, ifp) \
- if (RB_INSERT(if_index_head, &vrf->ifaces_by_index, (ifp))) \
- flog_err(EC_LIB_INTERFACE, \
- "%s(%u): corruption detected -- interface with this " \
- "ifindex exists already in VRF %u!", \
- __func__, (ifp)->ifindex, (ifp)->vrf_id);
-
-#define IFINDEX_RB_REMOVE(vrf, ifp) \
- if (RB_REMOVE(if_index_head, &vrf->ifaces_by_index, (ifp)) == NULL) \
- flog_err(EC_LIB_INTERFACE, \
- "%s(%u): corruption detected -- interface with this " \
- "ifindex doesn't exist in VRF %u!", \
- __func__, (ifp)->ifindex, (ifp)->vrf_id);
+#define IFNAME_RB_INSERT(vrf, ifp) \
+ ({ \
+ struct interface *_iz = \
+ RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp)); \
+ if (_iz) \
+ flog_err( \
+ EC_LIB_INTERFACE, \
+ "%s(%s): corruption detected -- interface with this " \
+ "name exists already in VRF %u!", \
+ __func__, (ifp)->name, (ifp)->vrf_id); \
+ _iz; \
+ })
+
+#define IFNAME_RB_REMOVE(vrf, ifp) \
+ ({ \
+ struct interface *_iz = \
+ RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)); \
+ if (_iz == NULL) \
+ flog_err( \
+ EC_LIB_INTERFACE, \
+ "%s(%s): corruption detected -- interface with this " \
+ "name doesn't exist in VRF %u!", \
+ __func__, (ifp)->name, (ifp)->vrf_id); \
+ _iz; \
+ })
+
+
+#define IFINDEX_RB_INSERT(vrf, ifp) \
+ ({ \
+ struct interface *_iz = RB_INSERT( \
+ if_index_head, &vrf->ifaces_by_index, (ifp)); \
+ if (_iz) \
+ flog_err( \
+ EC_LIB_INTERFACE, \
+ "%s(%u): corruption detected -- interface with this " \
+ "ifindex exists already in VRF %u!", \
+ __func__, (ifp)->ifindex, (ifp)->vrf_id); \
+ _iz; \
+ })
+
+#define IFINDEX_RB_REMOVE(vrf, ifp) \
+ ({ \
+ struct interface *_iz = RB_REMOVE( \
+ if_index_head, &vrf->ifaces_by_index, (ifp)); \
+ if (_iz == NULL) \
+ flog_err( \
+ EC_LIB_INTERFACE, \
+ "%s(%u): corruption detected -- interface with this " \
+ "ifindex doesn't exist in VRF %u!", \
+ __func__, (ifp)->ifindex, (ifp)->vrf_id); \
+ _iz; \
+ })
#define FOR_ALL_INTERFACES(vrf, ifp) \
if (vrf) \
@@ -502,7 +527,7 @@ extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
/* Sets the index and adds to index list */
-extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
+extern int if_set_index(struct interface *ifp, ifindex_t ifindex);
/* Sets the name and adds to name list */
extern void if_set_name(struct interface *ifp, const char *name);
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index c6372f1abb..cd7f79a04e 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -112,7 +112,7 @@ static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
/*
* convert an ipv4 mapped ipv6 address back to ipv4 address
*/
-static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6,
+static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
struct in_addr *in)
{
memset(in, 0, sizeof(struct in_addr));
diff --git a/lib/lib_vty.c b/lib/lib_vty.c
index 787da08e28..9c927ca4af 100644
--- a/lib/lib_vty.c
+++ b/lib/lib_vty.c
@@ -93,7 +93,7 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
#endif
);
} else {
- if (mt->n_alloc != 0) {
+ if (mt->n_max != 0) {
char size[32];
snprintf(size, sizeof(size), "%6zu", mt->size);
#ifdef HAVE_MALLOC_USABLE_SIZE
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 3622890e46..9a681103d4 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -717,7 +717,7 @@ struct thread_master *frr_init(void)
log_ref_vty_init();
lib_error_init();
- yang_init();
+ yang_init(true);
debug_init_cli();
diff --git a/lib/libfrr.h b/lib/libfrr.h
index f964c9e2a1..9d91ea9154 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -128,7 +128,8 @@ extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv);
extern void frr_opt_add(const char *optstr, const struct option *longopts,
const char *helpstr);
extern int frr_getopt(int argc, char *const argv[], int *longindex);
-extern void frr_help_exit(int status);
+
+extern __attribute__((__noreturn__)) void frr_help_exit(int status);
extern struct thread_master *frr_init(void);
extern const char *frr_get_progname(void);
diff --git a/lib/log.c b/lib/log.c
index 2101e0225c..b3be5216aa 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1228,59 +1228,47 @@ int proto_redistnum(int afi, const char *s)
return -1;
}
-void zlog_hexdump(const void *mem, unsigned int len)
+void zlog_hexdump(const void *mem, size_t len)
{
- unsigned long i = 0;
- unsigned int j = 0;
- unsigned int columns = 8;
- /*
- * 19 bytes for 0xADDRESS:
- * 24 bytes for data; 2 chars plus a space per data byte
- * 1 byte for space
- * 8 bytes for ASCII representation
- * 1 byte for a newline
- * =====================
- * 53 bytes per 8 bytes of data
- * 1 byte for null term
- */
- size_t bs = ((len / 8) + 1) * 53 + 1;
- char buf[bs];
- char *s = buf;
- const unsigned char *memch = mem;
-
- memset(buf, 0, sizeof(buf));
-
- for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0);
- i++) {
- /* print offset */
- if (i % columns == 0)
- s += snprintf(s, bs - (s - buf),
- "0x%016lx: ", (unsigned long)memch + i);
-
- /* print hex data */
- if (i < len)
- s += snprintf(s, bs - (s - buf), "%02x ", memch[i]);
-
- /* end of block, just aligning for ASCII dump */
- else
- s += snprintf(s, bs - (s - buf), " ");
-
- /* print ASCII dump */
- if (i % columns == (columns - 1)) {
- for (j = i - (columns - 1); j <= i; j++) {
- /* end of block not really printing */
- if (j >= len)
- s += snprintf(s, bs - (s - buf), " ");
- else if (isprint(memch[j]))
- s += snprintf(s, bs - (s - buf), "%c",
- memch[j]);
- else /* other char */
- s += snprintf(s, bs - (s - buf), ".");
- }
- s += snprintf(s, bs - (s - buf), "\n");
+ char line[64];
+ const uint8_t *src = mem;
+ const uint8_t *end = src + len;
+
+ if (len == 0) {
+ zlog_debug("%016lx: (zero length / no data)", (long)src);
+ return;
+ }
+
+ while (src < end) {
+ struct fbuf fb = {
+ .buf = line,
+ .pos = line,
+ .len = sizeof(line),
+ };
+ const uint8_t *lineend = src + 8;
+ unsigned line_bytes = 0;
+
+ bprintfrr(&fb, "%016lx: ", (long)src);
+
+ while (src < lineend && src < end) {
+ bprintfrr(&fb, "%02x ", *src++);
+ line_bytes++;
+ }
+ if (line_bytes < 8)
+ bprintfrr(&fb, "%*s", (8 - line_bytes) * 3, "");
+
+ src -= line_bytes;
+ while (src < lineend && src < end && fb.pos < fb.buf + fb.len) {
+ uint8_t byte = *src++;
+
+ if (isprint(byte))
+ *fb.pos++ = byte;
+ else
+ *fb.pos++ = '.';
}
+
+ zlog_debug("%.*s", (int)(fb.pos - fb.buf), fb.buf);
}
- zlog_debug("\n%s", buf);
}
const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, size_t inlen)
diff --git a/lib/log.h b/lib/log.h
index 501da88a54..d79ad9f805 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -152,7 +152,7 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter);
extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */,
char *buf, size_t buflen);
-extern void zlog_hexdump(const void *mem, unsigned int len);
+extern void zlog_hexdump(const void *mem, size_t len);
extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in,
size_t inlen);
diff --git a/lib/md5.c b/lib/md5.c
index 9c003a3af6..5c93c7bc1f 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -429,7 +429,7 @@ void hmac_md5(unsigned char *text, int text_len, unsigned char *key,
* pass */
MD5Update(&context, k_ipad, 64); /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
- MD5Final((uint8_t *)digest, &context); /* finish up 1st pass */
+ MD5Final(digest, &context); /* finish up 1st pass */
/*
* perform outer MD5
*/
@@ -438,5 +438,5 @@ void hmac_md5(unsigned char *text, int text_len, unsigned char *key,
MD5Update(&context, k_opad, 64); /* start with outer pad */
MD5Update(&context, digest, 16); /* then results of 1st
* hash */
- MD5Final((uint8_t *)digest, &context); /* finish up 2nd pass */
+ MD5Final(digest, &context); /* finish up 2nd pass */
}
diff --git a/lib/memory.h b/lib/memory.h
index 44ea19b557..e4e05faa4f 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -179,7 +179,8 @@ extern int qmem_walk(qmem_walk_fn *func, void *arg);
extern int log_memstats(FILE *fp, const char *);
#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
-extern void memory_oom(size_t size, const char *name);
+extern __attribute__((__noreturn__)) void memory_oom(size_t size,
+ const char *name);
#ifdef __cplusplus
}
diff --git a/lib/mlag.c b/lib/mlag.c
index 733dd41ea8..653fbe8fe9 100644
--- a/lib/mlag.c
+++ b/lib/mlag.c
@@ -85,9 +85,12 @@ int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg,
size_t *length)
{
#define LIB_MLAG_HDR_LENGTH 8
+ if (s == NULL || msg == NULL)
+ return -1;
+
*length = stream_get_endp(s);
- if (s == NULL || msg == NULL || *length < LIB_MLAG_HDR_LENGTH)
+ if (*length < LIB_MLAG_HDR_LENGTH)
return -1;
*length -= LIB_MLAG_HDR_LENGTH;
diff --git a/lib/monotime.h b/lib/monotime.h
index e246f177de..dda763784f 100644
--- a/lib/monotime.h
+++ b/lib/monotime.h
@@ -112,6 +112,26 @@ static inline char *time_to_string(time_t ts, char *buf)
return ctime_r(&tbuf, buf);
}
+/* Convert interval to human-friendly string, used in cli output e.g. */
+static inline const char *frrtime_to_interval(time_t t, char *buf,
+ size_t buflen)
+{
+ struct tm tm;
+
+ gmtime_r(&t, &tm);
+
+ if (t < ONE_DAY_SECOND)
+ snprintf(buf, buflen, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min,
+ tm.tm_sec);
+ else if (t < ONE_WEEK_SECOND)
+ snprintf(buf, buflen, "%dd%02dh%02dm", tm.tm_yday, tm.tm_hour,
+ tm.tm_min);
+ else
+ snprintf(buf, buflen, "%02dw%dd%02dh", tm.tm_yday / 7,
+ tm.tm_yday - ((tm.tm_yday / 7) * 7), tm.tm_hour);
+ return buf;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/mpls.c b/lib/mpls.c
index 759fe1206d..ac5792a686 100644
--- a/lib/mpls.c
+++ b/lib/mpls.c
@@ -79,7 +79,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
/*
* Label to string conversion, labels in string separated by '/'.
*/
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
int len, int pretty)
{
char label_buf[BUFSIZ];
diff --git a/lib/mpls.h b/lib/mpls.h
index 635ecc77a1..05cf2935e8 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -209,10 +209,13 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
int mpls_str2label(const char *label_str, uint8_t *num_labels,
mpls_label_t *labels);
+/* Generic string buffer for label-stack-to-str */
+#define MPLS_LABEL_STRLEN 1024
+
/*
* Label to string conversion, labels in string separated by '/'.
*/
-char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
+char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
int len, int pretty);
#ifdef __cplusplus
diff --git a/lib/nexthop.c b/lib/nexthop.c
index e23f8b0792..0d239e091b 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -23,11 +23,9 @@
#include "table.h"
#include "memory.h"
#include "command.h"
-#include "if.h"
#include "log.h"
#include "sockunion.h"
#include "linklist.h"
-#include "thread.h"
#include "prefix.h"
#include "nexthop.h"
#include "mpls.h"
@@ -155,7 +153,24 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
}
ret = _nexthop_source_cmp(next1, next2);
+ if (ret != 0)
+ goto done;
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return -1;
+
+ if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 1;
+
+ if (next1->backup_idx < next2->backup_idx)
+ return -1;
+ if (next1->backup_idx > next2->backup_idx)
+ return 1;
+
+done:
return ret;
}
@@ -240,7 +255,7 @@ struct nexthop *nexthop_new(void)
* The linux kernel does some weird stuff with adding +1 to
* all nexthop weights it gets over netlink.
* To handle this, just default everything to 1 right from
- * from the beggining so we don't have to special case
+ * from the beginning so we don't have to special case
* default weights in the linux netlink code.
*
* 1 should be a valid on all platforms anyway.
@@ -393,8 +408,8 @@ struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
}
/* Update nexthop with label information. */
-void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
- uint8_t num_labels, mpls_label_t *label)
+void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
+ uint8_t num_labels, const mpls_label_t *labels)
{
struct mpls_label_stack *nh_label;
int i;
@@ -402,23 +417,26 @@ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
if (num_labels == 0)
return;
- nexthop->nh_label_type = type;
+ /* Enforce limit on label stack size */
+ if (num_labels > MPLS_MAX_LABELS)
+ num_labels = MPLS_MAX_LABELS;
+
+ nexthop->nh_label_type = ltype;
+
nh_label = XCALLOC(MTYPE_NH_LABEL,
sizeof(struct mpls_label_stack)
+ num_labels * sizeof(mpls_label_t));
nh_label->num_labels = num_labels;
for (i = 0; i < num_labels; i++)
- nh_label->label[i] = *(label + i);
+ nh_label->label[i] = *(labels + i);
nexthop->nh_label = nh_label;
}
/* Free label information of nexthop, if present. */
void nexthop_del_labels(struct nexthop *nexthop)
{
- if (nexthop->nh_label) {
- XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
- nexthop->nh_label_type = ZEBRA_LSP_NONE;
- }
+ XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
+ nexthop->nh_label_type = ZEBRA_LSP_NONE;
}
const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
@@ -505,6 +523,7 @@ unsigned int nexthop_level(struct nexthop *nexthop)
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
+ uint32_t val;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
@@ -534,8 +553,12 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- key = jhash_2words(nexthop->ifindex,
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
+ val = 0;
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ val = (uint32_t)nexthop->backup_idx;
+
+ key = jhash_3words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val,
key);
return key;
@@ -575,6 +598,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
copy->type = nexthop->type;
copy->flags = nexthop->flags;
copy->weight = nexthop->weight;
+ copy->backup_idx = nexthop->backup_idx;
memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 6710914e40..c4e88dd844 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -86,6 +86,8 @@ struct nexthop {
* active one
*/
#define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */
+#define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */
+
#define NEXTHOP_IS_ACTIVE(flags) \
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
@@ -116,15 +118,31 @@ struct nexthop {
/* Weight of the nexthop ( for unequal cost ECMP ) */
uint8_t weight;
+
+ /* Index of a corresponding backup nexthop in a backup list;
+ * only meaningful if the HAS_BACKUP flag is set.
+ */
+ uint8_t backup_idx;
};
+/* Backup index value is limited */
+#define NEXTHOP_BACKUP_IDX_MAX 255
+
+/* Utility to append one nexthop to another. */
+#define NEXTHOP_APPEND(to, new) \
+ do { \
+ (to)->next = (new); \
+ (new)->prev = (to); \
+ (new)->next = NULL; \
+ } while (0)
+
struct nexthop *nexthop_new(void);
void nexthop_free(struct nexthop *nexthop);
void nexthops_free(struct nexthop *nexthop);
-void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t,
- mpls_label_t *);
+void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
+ uint8_t num_labels, const mpls_label_t *labels);
void nexthop_del_labels(struct nexthop *);
/*
@@ -201,6 +219,10 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop,
extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
struct nexthop *rparent);
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pNH" (struct nexthop *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index d660428bcd..a4c823e37a 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -43,8 +43,12 @@ struct nexthop_hold {
char *intf;
char *labels;
uint32_t weight;
+ int backup_idx; /* Index of backup nexthop, if >= 0 */
};
+/* Invalid/unset value for nexthop_hold's backup_idx */
+#define NHH_BACKUP_IDX_INVALID -1
+
struct nexthop_group_hooks {
void (*new)(const char *name);
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -143,6 +147,59 @@ struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
return NULL;
}
+/*
+ * Helper that locates a nexthop in an nhg config list. Note that
+ * this uses a specific matching / equality rule that's different from
+ * the complete match performed by 'nexthop_same()'.
+ */
+static struct nexthop *nhg_nh_find(const struct nexthop_group *nhg,
+ const struct nexthop *nh)
+{
+ struct nexthop *nexthop;
+ int ret;
+
+ /* We compare: vrf, gateway, and interface */
+
+ for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
+
+ /* Compare vrf and type */
+ if (nexthop->vrf_id != nh->vrf_id)
+ continue;
+ if (nexthop->type != nh->type)
+ continue;
+
+ /* Compare gateway */
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ ret = nexthop_g_addr_cmp(nexthop->type,
+ &nexthop->gate, &nh->gate);
+ if (ret != 0)
+ continue;
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ ret = nexthop_g_addr_cmp(nexthop->type,
+ &nexthop->gate, &nh->gate);
+ if (ret != 0)
+ continue;
+ /* Intentional Fall-Through */
+ case NEXTHOP_TYPE_IFINDEX:
+ if (nexthop->ifindex != nh->ifindex)
+ continue;
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ if (nexthop->bh_type != nh->bh_type)
+ continue;
+ break;
+ }
+
+ return nexthop;
+ }
+
+ return NULL;
+}
+
static bool
nexthop_group_equal_common(const struct nexthop_group *nhg1,
const struct nexthop_group *nhg2,
@@ -225,6 +282,10 @@ void nexthop_group_copy(struct nexthop_group *to,
void nexthop_group_delete(struct nexthop_group **nhg)
{
+ /* OK to call with NULL group */
+ if ((*nhg) == NULL)
+ return;
+
if ((*nhg)->nexthop)
nexthops_free((*nhg)->nexthop);
@@ -322,6 +383,25 @@ void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
nh->next = NULL;
}
+/* Unlink a nexthop from the list it's on, unconditionally */
+static void nexthop_unlink(struct nexthop_group *nhg, struct nexthop *nexthop)
+{
+
+ if (nexthop->prev)
+ nexthop->prev->next = nexthop->next;
+ else {
+ assert(nhg->nexthop == nexthop);
+ assert(nexthop->prev == NULL);
+ nhg->nexthop = nexthop->next;
+ }
+
+ if (nexthop->next)
+ nexthop->next->prev = nexthop->prev;
+
+ nexthop->prev = NULL;
+ nexthop->next = NULL;
+}
+
/*
* Copy a list of nexthops in 'nh' to an nhg, enforcing canonical sort order
*/
@@ -567,11 +647,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
return CMD_SUCCESS;
}
+DEFPY(nexthop_group_backup, nexthop_group_backup_cmd,
+ "backup-group WORD$name",
+ "Specify a group name containing backup nexthops\n"
+ "The name of the backup group\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name));
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
+ "no backup-group [WORD$name]",
+ NO_STR
+ "Clear group name containing backup nexthops\n"
+ "The name of the backup group\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ nhgc->backup_list_name[0] = 0;
+
+ return CMD_SUCCESS;
+}
+
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
const char *intf, const char *labels,
- const uint32_t weight)
+ const uint32_t weight, int backup_idx)
{
struct nexthop_hold *nh;
@@ -588,14 +693,22 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->weight = weight;
+ nh->backup_idx = backup_idx;
+
listnode_add_sort(nhgc->nhg_list, nh);
}
+/*
+ * Remove config info about a nexthop from group 'nhgc'. Note that we
+ * use only a subset of the available attributes here to determine
+ * a 'match'.
+ * Note that this doesn't change the list of nexthops, only the config
+ * information.
+ */
static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
- const char *intf, const char *labels,
- const uint32_t weight)
+ const char *intf)
{
struct nexthop_hold *nh;
struct listnode *node;
@@ -603,9 +716,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0
&& nhgc_addr_cmp_helper(addr, nh->addr) == 0
- && nhgc_cmp_helper(intf, nh->intf) == 0
- && nhgc_cmp_helper(labels, nh->labels) == 0
- && weight == nh->weight)
+ && nhgc_cmp_helper(intf, nh->intf) == 0)
break;
}
@@ -629,7 +740,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
const char *intf, const char *name,
const char *labels, int *lbl_ret,
- uint32_t weight)
+ uint32_t weight, int backup_idx)
{
int ret = 0;
struct vrf *vrf;
@@ -688,6 +799,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->weight = weight;
+ if (backup_idx != NHH_BACKUP_IDX_INVALID) {
+ /* Validate index value */
+ if (backup_idx > NEXTHOP_BACKUP_IDX_MAX)
+ return false;
+
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nhop->backup_idx = backup_idx;
+ }
+
return true;
}
@@ -699,7 +819,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
{
return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name, nhh->labels, NULL,
- nhh->weight));
+ nhh->weight, nhh->backup_idx));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -712,6 +832,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nexthop-vrf NAME$vrf_name \
|label WORD \
|weight (1-255) \
+ |backup-idx$bi_str (0-254)$idx \
}]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
@@ -724,16 +845,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"Specify label(s) for this nexthop\n"
"One or more labels in the range (16-1048575) separated by '/'\n"
"Weight to be used by the nexthop for purposes of ECMP\n"
- "Weight value to be used\n")
+ "Weight value to be used\n"
+ "Backup nexthop index in another group\n"
+ "Nexthop index value\n")
{
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct nexthop nhop;
struct nexthop *nh;
int lbl_ret = 0;
bool legal;
+ int backup_idx = idx;
+ bool yes = !no;
+
+ if (bi_str == NULL)
+ backup_idx = NHH_BACKUP_IDX_INVALID;
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
- &lbl_ret, weight);
+ &lbl_ret, weight, backup_idx);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -763,21 +891,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
return CMD_WARNING_CONFIG_FAILED;
}
- nh = nexthop_exists(&nhgc->nhg, &nhop);
+ /* Look for an existing nexthop in the config. Note that the test
+ * here tests only some attributes - it's not a complete comparison.
+ * Note that we've got two kinds of objects to manage: 'nexthop_hold'
+ * that represent config that may or may not be valid (yet), and
+ * actual nexthops that have been validated and parsed.
+ */
+ nh = nhg_nh_find(&nhgc->nhg, &nhop);
- if (no) {
- nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
- weight);
- if (nh) {
- _nexthop_del(&nhgc->nhg, nh);
+ /* Always attempt to remove old config info. */
+ nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf);
- if (nhg_hooks.del_nexthop)
- nhg_hooks.del_nexthop(nhgc, nh);
+ /* Remove any existing nexthop, for delete and replace cases. */
+ if (nh) {
+ nexthop_unlink(&nhgc->nhg, nh);
- nexthop_free(nh);
- }
- } else if (!nh) {
- /* must be adding new nexthop since !no and !nexthop_exists */
+ if (nhg_hooks.del_nexthop)
+ nhg_hooks.del_nexthop(nhgc, nh);
+
+ nexthop_free(nh);
+ }
+ if (yes) {
+ /* Add/replace case: capture nexthop if valid, and capture
+ * config info always.
+ */
if (legal) {
nh = nexthop_new();
@@ -785,8 +922,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
_nexthop_add(&nhgc->nhg.nexthop, nh);
}
+ /* Save config always */
nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
- weight);
+ weight, backup_idx);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
@@ -849,6 +987,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ vty_out(vty, " backup-idx %d", nh->backup_idx);
+
vty_out(vty, "\n");
}
@@ -874,6 +1015,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
+ if (nh->backup_idx != NHH_BACKUP_IDX_INVALID)
+ vty_out(vty, " backup-idx %d", nh->backup_idx);
+
vty_out(vty, "\n");
}
@@ -887,6 +1031,10 @@ static int nexthop_group_write(struct vty *vty)
vty_out(vty, "nexthop-group %s\n", nhgc->name);
+ if (nhgc->backup_list_name[0])
+ vty_out(vty, " backup-group %s\n",
+ nhgc->backup_list_name);
+
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
vty_out(vty, " ");
nexthop_group_write_nexthop_internal(vty, nh);
@@ -1067,6 +1215,8 @@ void nexthop_group_init(void (*new)(const char *name),
install_element(CONFIG_NODE, &no_nexthop_group_cmd);
install_default(NH_GROUP_NODE);
+ install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd);
+ install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);
install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
memset(&nhg_hooks, 0, sizeof(nhg_hooks));
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index f99a53f694..3a5a1299c1 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -57,6 +57,8 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg);
uint32_t nexthop_group_hash(const struct nexthop_group *nhg);
void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
+
+/* Add a nexthop to a list, enforcing the canonical sort order. */
void nexthop_group_add_sorted(struct nexthop_group *nhg,
struct nexthop *nexthop);
@@ -79,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,
(nhop) = nexthop_next(nhop)
+#define NHGC_NAME_SIZE 80
+
struct nexthop_group_cmd {
RB_ENTRY(nexthop_group_cmd) nhgc_entry;
- char name[80];
+ char name[NHGC_NAME_SIZE];
+
+ /* Name of group containing backup nexthops (if set) */
+ char backup_list_name[NHGC_NAME_SIZE];
struct nexthop_group nhg;
diff --git a/lib/northbound.c b/lib/northbound.c
index cebedcff09..85e723d7cf 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -1866,6 +1866,13 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
struct nb_node *nb_node;
uint32_t priority;
+ if (i > YANG_MODULE_MAX_NODES) {
+ zlog_err(
+ "%s: %s.yang has more than %u nodes. Please increase YANG_MODULE_MAX_NODES to fix this problem.",
+ __func__, module->name, YANG_MODULE_MAX_NODES);
+ exit(1);
+ }
+
nb_node = nb_node_find(module->nodes[i].xpath);
if (!nb_node) {
flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH,
diff --git a/lib/northbound.h b/lib/northbound.h
index 76a11e518c..19a2ba0865 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -403,6 +403,13 @@ struct nb_node {
/* The YANG list doesn't contain key leafs. */
#define F_NB_NODE_KEYLESS_LIST 0x02
+/*
+ * HACK: old gcc versions (< 5.x) have a bug that prevents C99 flexible arrays
+ * from working properly on shared libraries. For those compilers, use a fixed
+ * size array to work around the problem.
+ */
+#define YANG_MODULE_MAX_NODES 1024
+
struct frr_yang_module_info {
/* YANG module name. */
const char *name;
@@ -417,7 +424,11 @@ struct frr_yang_module_info {
/* Priority - lower priorities are processed first. */
uint32_t priority;
+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
+ } nodes[YANG_MODULE_MAX_NODES + 1];
+#else
} nodes[];
+#endif
};
/* Northbound error codes. */
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 089899368d..b195f1aeca 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -884,7 +884,14 @@ static int frr_grpc_finish(void)
return 0;
}
-static int frr_grpc_module_late_init(struct thread_master *tm)
+/*
+ * This is done this way because module_init and module_late_init are both
+ * called during daemon pre-fork initialization. Because the GRPC library
+ * spawns threads internally, we need to delay initializing it until after
+ * fork. This is done by scheduling this init function as an event task, since
+ * the event loop doesn't run until after fork.
+ */
+static int frr_grpc_module_very_late_init(struct thread *thread)
{
static unsigned long port = GRPC_DEFAULT_PORT;
const char *args = THIS_MODULE->load_args;
@@ -910,15 +917,19 @@ static int frr_grpc_module_late_init(struct thread_master *tm)
if (frr_grpc_init(&port) < 0)
goto error;
- hook_register(frr_fini, frr_grpc_finish);
-
- return 0;
-
error:
flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module");
return -1;
}
+static int frr_grpc_module_late_init(struct thread_master *tm)
+{
+ thread_add_event(tm, frr_grpc_module_very_late_init, NULL, 0, NULL);
+ hook_register(frr_fini, frr_grpc_finish);
+
+ return 0;
+}
+
static int frr_grpc_module_init(void)
{
hook_register(frr_late_init, frr_grpc_module_late_init);
diff --git a/lib/ntop.c b/lib/ntop.c
index 066e10e3e4..ccbf8793d3 100644
--- a/lib/ntop.c
+++ b/lib/ntop.c
@@ -165,7 +165,7 @@ inet4:
return dst;
}
-#ifndef INET_NTOP_NO_OVERRIDE
+#if !defined(INET_NTOP_NO_OVERRIDE) && !defined(__APPLE__)
/* we want to override libc inet_ntop, but make sure it shows up in backtraces
* as frr_inet_ntop (to avoid confusion while debugging)
*/
diff --git a/lib/plist.c b/lib/plist.c
index 40131aebed..b7a020c6f7 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -778,7 +778,7 @@ static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist)
p = &pentry->prefix;
- printf(" seq %" PRId64 " %s %s/%d", pentry->seq,
+ printf(" seq %lld %s %s/%d", (long long)pentry->seq,
prefix_list_type_str(pentry),
inet_ntop(p->family, p->u.val, buf, BUFSIZ),
p->prefixlen);
diff --git a/lib/prefix.h b/lib/prefix.h
index b01f7d1fdc..f2952c38c3 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -531,7 +531,7 @@ static inline int is_host_route(struct prefix *p)
return 0;
}
-static inline int is_default_host_route(struct prefix *p)
+static inline int is_default_host_route(const struct prefix *p)
{
if (p->family == AF_INET) {
return (p->u.prefix4.s_addr == INADDR_ANY &&
@@ -544,6 +544,22 @@ static inline int is_default_host_route(struct prefix *p)
return 0;
}
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
+#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
+
+#pragma FRR printfrr_ext "%pI6" (struct in6_addr *)
+
+#pragma FRR printfrr_ext "%pFX" (struct prefix *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv4 *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv6 *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *)
+#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *)
+
+#pragma FRR printfrr_ext "%pSG4" (struct prefix_sg *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/printfrr.h b/lib/printfrr.h
index f9584bcacc..7d9e288655 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -30,8 +30,7 @@ struct fbuf {
size_t len;
};
-#define at(a, b) \
- __attribute__((format(printf, a, b)))
+#define at(a, b) PRINTFRR(a, b)
#define atn(a, b) \
at(a, b) __attribute__((nonnull(1) _RET_NONNULL))
#define atm(a, b) \
@@ -73,8 +72,19 @@ char *vasnprintfrr(struct memtype *mt, char *out, size_t sz,
char *asnprintfrr(struct memtype *mt, char *out, size_t sz,
const char *fmt, ...) atn(4, 5);
+#define printfrr(fmt, ...) \
+ do { \
+ char buf[256], *out; \
+ out = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt, \
+ ##__VA_ARGS__); \
+ fputs(out, stdout); \
+ if (out != buf) \
+ XFREE(MTYPE_TMP, out); \
+ } while (0)
+
#undef at
#undef atm
+#undef atn
/* extension specs must start with a capital letter (this is a restriction
* for both performance's and human understanding's sake.)
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 5b03b5266f..41e8cacd81 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -148,6 +148,12 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
SKIP_RULE("ipv6 next-hop type");
SKIP_RULE("metric");
SKIP_RULE("tag");
+ /* Zebra specific match conditions. */
+ SKIP_RULE("ip address prefix-len");
+ SKIP_RULE("ipv6 address prefix-len");
+ SKIP_RULE("ip next-hop prefix-len");
+ SKIP_RULE("source-protocol");
+ SKIP_RULE("source-instance");
vty_out(vty, " match %s %s\n", rmr->cmd->str,
rmr->rule_str ? rmr->rule_str : "");
@@ -158,6 +164,8 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
/* Skip all sets implemented by northbound. */
SKIP_RULE("metric");
SKIP_RULE("tag");
+ /* Zebra specific set actions. */
+ SKIP_RULE("src");
vty_out(vty, " set %s %s\n", rmr->cmd->str,
rmr->rule_str ? rmr->rule_str : "");
@@ -666,8 +674,25 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " match tag %s\n",
yang_dnode_get_string(dnode, "./tag"));
break;
- case 100:
- /* NOTHING: custom field, should be handled by daemon. */
+ case 100: /* ipv4-prefix-length */
+ vty_out(vty, " match ip address prefix-len %s\n",
+ yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length"));
+ break;
+ case 101: /* ipv6-prefix-length */
+ vty_out(vty, " match ipv6 address prefix-len %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length"));
+ break;
+ case 102: /* ipv4-next-hop-prefix-length */
+ vty_out(vty, " match ip next-hop prefix-len %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length"));
+ break;
+ case 103: /* source-protocol */
+ vty_out(vty, " match source-protocol %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-protocol"));
+ break;
+ case 104: /* source-instance */
+ vty_out(vty, " match source-instance %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-instance"));
break;
}
}
@@ -868,8 +893,13 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " set tag %s\n",
yang_dnode_get_string(dnode, "./tag"));
break;
- case 100:
- /* NOTHING: custom field, should be handled by daemon. */
+ case 100: /* source */
+ if (yang_dnode_exists(dnode, "./frr-zebra:source-v4"))
+ vty_out(vty, " set src %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-v4"));
+ else
+ vty_out(vty, " set src %s\n",
+ yang_dnode_get_string(dnode, "./frr-zebra:source-v6"));
break;
}
}
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index 69cebbd2a1..dd4cbd7d99 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -1221,32 +1221,7 @@ lib_route_map_entry_set_action_tag_destroy(enum nb_event event,
}
/* clang-format off */
-#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
-/*
- * gcc versions before 5.x miscalculate the size for structs with variable
- * length arrays (they just count it as size 0)
- */
-struct frr_yang_module_info_sizen {
- /* YANG module name. */
- const char *name;
-
- /* Northbound callbacks. */
- const struct {
- /* Data path of this YANG node. */
- const char *xpath;
-
- /* Callbacks implemented for this node. */
- struct nb_callbacks cbs;
-
- /* Priority - lower priorities are processed first. */
- uint32_t priority;
- } nodes[28];
-};
-
-const struct frr_yang_module_info_sizen frr_route_map_info_sizen asm("frr_route_map_info") = {
-#else
const struct frr_yang_module_info frr_route_map_info = {
-#endif
.name = "frr-route-map",
.nodes = {
{
diff --git a/lib/skiplist.c b/lib/skiplist.c
index d955c6eb9e..790bd71c38 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -112,7 +112,7 @@ static int randomLevel(void)
return level;
}
-static int default_cmp(void *key1, void *key2)
+static int default_cmp(const void *key1, const void *key2)
{
if (key1 < key2)
return -1;
@@ -126,7 +126,8 @@ unsigned int skiplist_count(struct skiplist *l)
return l->count;
}
-struct skiplist *skiplist_new(int flags, int (*cmp)(void *key1, void *key2),
+struct skiplist *skiplist_new(int flags,
+ int (*cmp)(const void *key1, const void *key2),
void (*del)(void *val))
{
struct skiplist *new;
@@ -329,8 +330,8 @@ int skiplist_delete(register struct skiplist *l, register void *key,
* Also set a cursor for use with skiplist_next_value.
*/
int skiplist_first_value(register struct skiplist *l, /* in */
- register void *key, /* in */
- void **valuePointer, /* out */
+ register const void *key, /* in */
+ void **valuePointer, /* out */
void **cursor) /* out */
{
register int k;
@@ -374,7 +375,7 @@ int skiplist_search(register struct skiplist *l, register void *key,
* last element with the given key, -1 is returned.
*/
int skiplist_next_value(register struct skiplist *l, /* in */
- register void *key, /* in */
+ register const void *key, /* in */
void **valuePointer, /* in/out */
void **cursor) /* in/out */
{
@@ -623,7 +624,7 @@ void skiplist_test(struct vty *vty)
zlog_debug("%s: (%d:%d)", __func__, i, k);
}
// keys[k] = (void *)random();
- keys[k] = (void *)scramble(k);
+ keys[k] = scramble(k);
if (skiplist_insert(l, keys[k], keys[k]))
zlog_debug("error in insert #%d,#%d", i, k);
}
@@ -648,7 +649,7 @@ void skiplist_test(struct vty *vty)
zlog_debug("<%d:%d>", i, k);
if (skiplist_delete(l, keys[k], keys[k]))
zlog_debug("error in delete");
- keys[k] = (void *)scramble(k ^ 0xf0f0f0f0);
+ keys[k] = scramble(k ^ 0xf0f0f0f0);
if (skiplist_insert(l, keys[k], keys[k]))
zlog_debug("error in insert #%d,#%d", i, k);
}
diff --git a/lib/skiplist.h b/lib/skiplist.h
index 2ab37331c9..a106a455d6 100644
--- a/lib/skiplist.h
+++ b/lib/skiplist.h
@@ -68,7 +68,7 @@ struct skiplist {
* Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
* Used as definition of sorted for listnode_add_sort
*/
- int (*cmp)(void *val1, void *val2);
+ int (*cmp)(const void *val1, const void *val2);
/* callback to free user-owned data when listnode is deleted. supplying
* this callback is very much encouraged!
@@ -81,8 +81,9 @@ struct skiplist {
extern struct skiplist *
skiplist_new(/* encouraged: set list.del callback on new lists */
int flags,
- int (*cmp)(void *key1, void *key2), /* NULL => default cmp */
- void (*del)(void *val)); /* NULL => no auto val free */
+ int (*cmp)(const void *key1,
+ const void *key2), /* NULL => default cmp */
+ void (*del)(void *val)); /* NULL => no auto val free */
extern void skiplist_free(struct skiplist *);
@@ -96,12 +97,12 @@ extern int skiplist_search(register struct skiplist *l, register void *key,
void **valuePointer);
extern int skiplist_first_value(register struct skiplist *l, /* in */
- register void *key, /* in */
- void **valuePointer, /* in/out */
+ register const void *key, /* in */
+ void **valuePointer, /* in/out */
void **cursor); /* out */
extern int skiplist_next_value(register struct skiplist *l, /* in */
- register void *key, /* in */
+ register const void *key, /* in */
void **valuePointer, /* in/out */
void **cursor); /* in/out */
diff --git a/lib/smux.h b/lib/smux.h
index 3f860db0dc..6896f02354 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -105,7 +105,7 @@ extern int smux_trap(struct variable *, size_t, const oid *, size_t,
extern int oid_compare(const oid *, int, const oid *, int);
extern void oid2in_addr(oid[], int, struct in_addr *);
extern void *oid_copy(void *, const void *, size_t);
-extern void oid_copy_addr(oid[], struct in_addr *, int);
+extern void oid_copy_addr(oid[], const struct in_addr *, int);
#ifdef __cplusplus
}
diff --git a/lib/snmp.c b/lib/snmp.c
index f11d9dc8cf..736a3c62b8 100644
--- a/lib/snmp.c
+++ b/lib/snmp.c
@@ -64,10 +64,10 @@ void oid2in_addr(oid oid[], int len, struct in_addr *addr)
*pnt++ = oid[i];
}
-void oid_copy_addr(oid oid[], struct in_addr *addr, int len)
+void oid_copy_addr(oid oid[], const struct in_addr *addr, int len)
{
int i;
- uint8_t *pnt;
+ const uint8_t *pnt;
if (len == 0)
return;
diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c
index 41d4e2bb57..4e74714489 100644
--- a/lib/spf_backoff.c
+++ b/lib/spf_backoff.c
@@ -7,7 +7,7 @@
* Copyright (C) 2017 Orange Labs http://www.orange.com/
* Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF 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
diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h
index 11b2701e3e..2617195d79 100644
--- a/lib/spf_backoff.h
+++ b/lib/spf_backoff.h
@@ -7,7 +7,7 @@
* Copyright (C) 2017 Orange Labs http://www.orange.com/
* Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF 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
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index ee87d73077..66b735919b 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by David Lamparter & Christian Franke,
* Open Source Routing / NetDEF 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
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 90418944c7..7982260777 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -4,7 +4,7 @@
* Copyright (C) 2017 by David Lamparter & Christian Franke,
* Open Source Routing / NetDEF 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
diff --git a/lib/stream.c b/lib/stream.c
index dd4d5bd96d..683a130e44 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -543,6 +543,27 @@ uint64_t stream_getq(struct stream *s)
return q;
}
+bool stream_getq2(struct stream *s, uint64_t *q)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (STREAM_READABLE(s) < sizeof(uint64_t)) {
+ STREAM_BOUND_WARN2(s, "get uint64");
+ return false;
+ }
+
+ *q = ((uint64_t)s->data[s->getp++]) << 56;
+ *q |= ((uint64_t)s->data[s->getp++]) << 48;
+ *q |= ((uint64_t)s->data[s->getp++]) << 40;
+ *q |= ((uint64_t)s->data[s->getp++]) << 32;
+ *q |= ((uint64_t)s->data[s->getp++]) << 24;
+ *q |= ((uint64_t)s->data[s->getp++]) << 16;
+ *q |= ((uint64_t)s->data[s->getp++]) << 8;
+ *q |= ((uint64_t)s->data[s->getp++]);
+
+ return true;
+}
+
/* Get next long word from the stream. */
uint32_t stream_get_ipv4(struct stream *s)
{
@@ -898,7 +919,7 @@ int stream_put_prefix(struct stream *s, const struct prefix *p)
}
/* Put NLRI with label */
-int stream_put_labeled_prefix(struct stream *s, struct prefix *p,
+int stream_put_labeled_prefix(struct stream *s, const struct prefix *p,
mpls_label_t *label, int addpath_encode,
uint32_t addpath_tx_id)
{
diff --git a/lib/stream.h b/lib/stream.h
index 36c65afa3c..5c7d94fab8 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -196,7 +196,7 @@ extern int stream_put_prefix_addpath(struct stream *s,
int addpath_encode,
uint32_t addpath_tx_id);
extern int stream_put_prefix(struct stream *s, const struct prefix *p);
-extern int stream_put_labeled_prefix(struct stream *, struct prefix *,
+extern int stream_put_labeled_prefix(struct stream *, const struct prefix *,
mpls_label_t *, int addpath_encode,
uint32_t addpath_tx_id);
extern void stream_get(void *, struct stream *, size_t);
@@ -215,6 +215,7 @@ extern bool stream_getl2(struct stream *s, uint32_t *l);
extern uint32_t stream_getl_from(struct stream *, size_t);
extern uint64_t stream_getq(struct stream *);
extern uint64_t stream_getq_from(struct stream *, size_t);
+bool stream_getq2(struct stream *s, uint64_t *q);
extern uint32_t stream_get_ipv4(struct stream *);
/* IEEE-754 floats */
@@ -354,9 +355,10 @@ extern void stream_fifo_free(struct stream_fifo *fifo);
* bit), for 64-bit values (you need to cast them anyway), and neither for
* encoding (because it's downcasted.)
*/
-static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out)
+static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
{
uint32_t tmp;
+
memcpy(&tmp, ptr, sizeof(tmp));
*out = ntohl(tmp);
return ptr + 4;
@@ -401,6 +403,25 @@ static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out)
(P) = _pval; \
} while (0)
+#define STREAM_GETF(S, P) \
+ do { \
+ union { \
+ float r; \
+ uint32_t d; \
+ } _pval; \
+ if (stream_getl2((S), &_pval.d)) \
+ goto stream_failure; \
+ (P) = _pval.r; \
+ } while (0)
+
+#define STREAM_GETQ(S, P) \
+ do { \
+ uint64_t _pval; \
+ if (!stream_getq2((S), &_pval)) \
+ goto stream_failure; \
+ (P) = _pval; \
+ } while (0)
+
#define STREAM_GET(P, STR, SIZE) \
do { \
if (!stream_get2((P), (STR), (SIZE))) \
diff --git a/lib/table.c b/lib/table.c
index 1a89a95f4f..86347cbacd 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -160,7 +160,7 @@ static void route_common(const struct prefix *n, const struct prefix *p,
np = (const uint8_t *)&n->u.prefix;
pp = (const uint8_t *)&p->u.prefix;
- newp = (uint8_t *)&new->u.prefix;
+ newp = &new->u.prefix;
for (i = 0; i < p->prefixlen / 8; i++) {
if (np[i] == pp[i])
diff --git a/lib/table.h b/lib/table.h
index 7743d51681..9cd9503376 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -331,6 +331,10 @@ static inline int route_table_iter_started(route_table_iter_t *iter)
return iter->state != RT_ITER_STATE_INIT;
}
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pRN" (struct route_node *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/thread.c b/lib/thread.c
index 2217a60f0a..dbf668a699 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -114,11 +114,10 @@ static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
- (size_t)a->total_active,
- a->cpu.total / 1000, a->cpu.total % 1000,
- (size_t)a->total_calls,
- a->cpu.total / a->total_calls, a->cpu.max,
- a->real.total / a->total_calls, a->real.max);
+ (size_t)a->total_active, a->cpu.total / 1000,
+ a->cpu.total % 1000, (size_t)a->total_calls,
+ (size_t)(a->cpu.total / a->total_calls), a->cpu.max,
+ (size_t)(a->real.total / a->total_calls), a->real.max);
vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
diff --git a/lib/vrf.c b/lib/vrf.c
index 370a1b235a..f642aa5609 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -116,7 +116,7 @@ static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr)
vrf->vrf_id = vrf_id;
RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
if (old_vrf_id == VRF_UNKNOWN)
- vrf_enable((struct vrf *)vrf);
+ vrf_enable(vrf);
}
int vrf_switch_to_netns(vrf_id_t vrf_id)
@@ -324,10 +324,7 @@ const char *vrf_id_to_name(vrf_id_t vrf_id)
struct vrf *vrf;
vrf = vrf_lookup_by_id(vrf_id);
- if (vrf)
- return vrf->name;
-
- return "n/a";
+ return VRF_LOGNAME(vrf);
}
vrf_id_t vrf_name_to_id(const char *name)
@@ -593,10 +590,22 @@ int vrf_get_backend(void)
return vrf_backend;
}
-void vrf_configure_backend(int vrf_backend_netns)
+int vrf_configure_backend(enum vrf_backend_type backend)
{
- vrf_backend = vrf_backend_netns;
+ /* Work around issue in old gcc */
+ switch (backend) {
+ case VRF_BACKEND_UNKNOWN:
+ case VRF_BACKEND_NETNS:
+ case VRF_BACKEND_VRF_LITE:
+ break;
+ default:
+ return -1;
+ }
+
+ vrf_backend = backend;
vrf_backend_configured = 1;
+
+ return 0;
}
int vrf_handler_create(struct vty *vty, const char *vrfname,
diff --git a/lib/vrf.h b/lib/vrf.h
index f231d2433f..2dc2648837 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -101,9 +101,12 @@ RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
DECLARE_QOBJ_TYPE(vrf)
/* Allow VRF with netns as backend */
-#define VRF_BACKEND_VRF_LITE 0
-#define VRF_BACKEND_NETNS 1
-#define VRF_BACKEND_UNKNOWN 2
+enum vrf_backend_type {
+ VRF_BACKEND_VRF_LITE,
+ VRF_BACKEND_NETNS,
+ VRF_BACKEND_UNKNOWN,
+ VRF_BACKEND_MAX,
+};
extern struct vrf_id_head vrfs_by_id;
extern struct vrf_name_head vrfs_by_name;
@@ -292,10 +295,10 @@ extern void vrf_install_commands(void);
* VRF utilities
*/
-/* API for configuring VRF backend
- * should be called from zebra only
+/*
+ * API for configuring VRF backend
*/
-extern void vrf_configure_backend(int vrf_backend_netns);
+extern int vrf_configure_backend(enum vrf_backend_type backend);
extern int vrf_get_backend(void);
extern int vrf_is_backend_netns(void);
diff --git a/lib/vty.c b/lib/vty.c
index 4dd6ec1b35..8056236de9 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -231,8 +231,13 @@ int vty_out(struct vty *vty, const char *format, ...)
strlen(filtered));
break;
case VTY_SHELL:
- fprintf(vty->of, "%s", filtered);
- fflush(vty->of);
+ if (vty->of) {
+ fprintf(vty->of, "%s", filtered);
+ fflush(vty->of);
+ } else if (vty->of_saved) {
+ fprintf(vty->of_saved, "%s", filtered);
+ fflush(vty->of_saved);
+ }
break;
case VTY_SHELL_SERV:
case VTY_FILE:
diff --git a/lib/yang.c b/lib/yang.c
index 93e6db3055..0502d4952d 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -628,7 +628,7 @@ void yang_debugging_set(bool enable)
}
}
-struct ly_ctx *yang_ctx_new_setup(void)
+struct ly_ctx *yang_ctx_new_setup(bool embedded_modules)
{
struct ly_ctx *ctx;
const char *yang_models_path = YANG_MODELS_PATH;
@@ -647,18 +647,21 @@ struct ly_ctx *yang_ctx_new_setup(void)
ctx = ly_ctx_new(yang_models_path, LY_CTX_DISABLE_SEARCHDIR_CWD);
if (!ctx)
return NULL;
- ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
+
+ if (embedded_modules)
+ ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL);
+
return ctx;
}
-void yang_init(void)
+void yang_init(bool embedded_modules)
{
/* Initialize libyang global parameters that affect all containers. */
ly_set_log_clb(ly_log_cb, 1);
ly_log_options(LY_LOLOG | LY_LOSTORE);
/* Initialize libyang container for native models. */
- ly_native_ctx = yang_ctx_new_setup();
+ ly_native_ctx = yang_ctx_new_setup(embedded_modules);
if (!ly_native_ctx) {
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
exit(1);
diff --git a/lib/yang.h b/lib/yang.h
index 6892e36019..8af440d3ed 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -482,8 +482,11 @@ extern struct yang_data *yang_data_list_find(const struct list *list,
/*
* Create and set up a libyang context (for use by the translator)
+ *
+ * embedded_modules
+ * Specify whether libyang should attempt to look for embedded YANG modules.
*/
-extern struct ly_ctx *yang_ctx_new_setup(void);
+extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules);
/*
* Enable or disable libyang verbose debugging.
@@ -496,8 +499,11 @@ extern void yang_debugging_set(bool enable);
/*
* Initialize the YANG subsystem. Should be called only once during the
* daemon initialization process.
+ *
+ * embedded_modules
+ * Specify whether libyang should attempt to look for embedded YANG modules.
*/
-extern void yang_init(void);
+extern void yang_init(bool embedded_modules);
/*
* Finish the YANG subsystem gracefully. Should be called only when the daemon
diff --git a/lib/yang_translator.c b/lib/yang_translator.c
index 341420eeda..7dbb1f3f1a 100644
--- a/lib/yang_translator.c
+++ b/lib/yang_translator.c
@@ -171,7 +171,7 @@ struct yang_translator *yang_translator_load(const char *path)
RB_INSERT(yang_translators, &yang_translators, translator);
/* Initialize the translator libyang context. */
- translator->ly_ctx = yang_ctx_new_setup();
+ translator->ly_ctx = yang_ctx_new_setup(false);
if (!translator->ly_ctx) {
flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
goto error;
@@ -511,7 +511,7 @@ static unsigned int yang_module_nodes_count(const struct lys_module *module)
void yang_translator_init(void)
{
- ly_translator_ctx = yang_ctx_new_setup();
+ ly_translator_ctx = yang_ctx_new_setup(true);
if (!ly_translator_ctx) {
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
exit(1);
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index a308b18b73..2b502d635b 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -22,6 +22,7 @@
#include "log.h"
#include "lib_errors.h"
#include "northbound.h"
+#include "printfrr.h"
static const char *yang_get_default_value(const char *xpath)
{
@@ -443,7 +444,7 @@ struct yang_data *yang_data_new_int64(const char *xpath, int64_t value)
{
char value_str[BUFSIZ];
- snprintf(value_str, sizeof(value_str), "%" PRId64, value);
+ snprintfrr(value_str, sizeof(value_str), "%" PRId64, value);
return yang_data_new(xpath, value_str);
}
@@ -651,7 +652,7 @@ struct yang_data *yang_data_new_uint64(const char *xpath, uint64_t value)
{
char value_str[BUFSIZ];
- snprintf(value_str, sizeof(value_str), "%" PRIu64, value);
+ snprintfrr(value_str, sizeof(value_str), "%" PRIu64, value);
return yang_data_new(xpath, value_str);
}
diff --git a/lib/zclient.c b/lib/zclient.c
index eac6c7081d..5402e9c3c5 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -52,7 +52,8 @@ static void zclient_event(enum event, struct zclient *);
static void zebra_interface_if_set_value(struct stream *s,
struct interface *ifp);
-struct zclient_options zclient_options_default = {.receive_notify = false};
+struct zclient_options zclient_options_default = {.receive_notify = false,
+ .synchronous = false};
struct sockaddr_storage zclient_addr;
socklen_t zclient_addr_len;
@@ -76,6 +77,7 @@ struct zclient *zclient_new(struct thread_master *master,
zclient->master = master;
zclient->receive_notify = opt->receive_notify;
+ zclient->synchronous = opt->synchronous;
return zclient;
}
@@ -374,11 +376,11 @@ static int zebra_message_send(struct zclient *zclient, int command,
return zclient_send_message(zclient);
}
-static int zebra_hello_send(struct zclient *zclient)
+int zclient_send_hello(struct zclient *zclient)
{
struct stream *s;
- if (zclient->redist_default) {
+ if (zclient->redist_default || zclient->synchronous) {
s = zclient->obuf;
stream_reset(s);
@@ -390,6 +392,10 @@ static int zebra_hello_send(struct zclient *zclient)
stream_putc(s, 1);
else
stream_putc(s, 0);
+ if (zclient->synchronous)
+ stream_putc(s, 1);
+ else
+ stream_putc(s, 0);
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
@@ -629,7 +635,7 @@ int zclient_start(struct zclient *zclient)
/* Create read thread. */
zclient_event(ZCLIENT_READ, zclient);
- zebra_hello_send(zclient);
+ zclient_send_hello(zclient);
zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
@@ -690,8 +696,9 @@ static int zclient_connect(struct thread *t)
return zclient_start(zclient);
}
-int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p,
- bool exact_match, vrf_id_t vrf_id)
+int zclient_send_rnh(struct zclient *zclient, int command,
+ const struct prefix *p, bool exact_match,
+ vrf_id_t vrf_id)
{
struct stream *s;
@@ -897,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
}
}
+ /* If present, set 'weight' flag before encoding flags */
if (api_nh->weight)
SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT);
@@ -941,6 +949,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
stream_put(s, &(api_nh->rmac),
sizeof(struct ethaddr));
+ /* Index of backup nexthop */
+ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
+ stream_putc(s, api_nh->backup_idx);
+
done:
return ret;
}
@@ -978,7 +990,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
stream_putc(s, api->prefix.family);
psize = PSIZE(api->prefix.prefixlen);
stream_putc(s, api->prefix.prefixlen);
- stream_write(s, (uint8_t *)&api->prefix.u.prefix, psize);
+ stream_write(s, &api->prefix.u.prefix, psize);
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) {
psize = PSIZE(api->src_prefix.prefixlen);
@@ -1000,6 +1012,10 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
return -1;
}
+ /* We canonicalize the nexthops by sorting them; this allows
+ * zebra to resolve the list of nexthops to a nexthop-group
+ * more efficiently.
+ */
zapi_nexthop_group_sort(api->nexthops, api->nexthop_num);
stream_putw(s, api->nexthop_num);
@@ -1026,6 +1042,50 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
}
}
+ /* Backup nexthops */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
+ /* limit the number of nexthops if necessary */
+ if (api->backup_nexthop_num > MULTIPATH_NUM) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+ flog_err(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: prefix %s: can't encode %u backup nexthops (maximum is %u)",
+ __func__, buf, api->backup_nexthop_num,
+ MULTIPATH_NUM);
+ return -1;
+ }
+
+ /* Note that we do not sort the list of backup nexthops -
+ * this list is treated as an array and indexed by each
+ * primary nexthop that is associated with a backup.
+ */
+
+ stream_putw(s, api->backup_nexthop_num);
+
+ for (i = 0; i < api->backup_nexthop_num; i++) {
+ api_nh = &api->backup_nexthops[i];
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: prefix %s: backup: can't encode %u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
+ }
+
+ if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
+ return -1;
+ }
+ }
+
/* Attributes. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc(s, api->distance);
@@ -1101,6 +1161,10 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
STREAM_GET(&(api_nh->rmac), s,
sizeof(struct ethaddr));
+ /* Backup nexthop index */
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
+ STREAM_GETC(s, api_nh->backup_idx);
+
/* Success */
ret = 0;
@@ -1207,6 +1271,24 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
}
}
+ /* Backup nexthops. */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
+ STREAM_GETW(s, api->backup_nexthop_num);
+ if (api->backup_nexthop_num > MULTIPATH_NUM) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: invalid number of backup nexthops (%u)",
+ __func__, api->backup_nexthop_num);
+ return -1;
+ }
+
+ for (i = 0; i < api->backup_nexthop_num; i++) {
+ api_nh = &api->backup_nexthops[i];
+
+ if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
+ return -1;
+ }
+ }
+
/* Attributes. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
STREAM_GETC(s, api->distance);
@@ -1381,7 +1463,7 @@ stream_failure:
return false;
}
-struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
+struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
{
struct nexthop *n = nexthop_new();
@@ -1398,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
znh->labels);
}
+ if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ n->backup_idx = znh->backup_idx;
+ }
+
return n;
}
@@ -1413,10 +1500,16 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
znh->type = nh->type;
znh->vrf_id = nh->vrf_id;
+ znh->weight = nh->weight;
znh->ifindex = nh->ifindex;
znh->gate = nh->gate;
if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
+
+ /* Validate */
+ if (nh->nh_label->num_labels > MPLS_MAX_LABELS)
+ return -1;
+
for (i = 0; i < nh->nh_label->num_labels; i++)
znh->labels[i] = nh->nh_label->label[i];
@@ -1424,10 +1517,31 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
}
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+ znh->backup_idx = nh->backup_idx;
+ }
+
return 0;
}
/*
+ * Wrapper that converts backup nexthop
+ */
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh)
+{
+ int ret;
+
+ /* Ensure that zapi flags are correct: backups don't have backups */
+ ret = zapi_nexthop_from_nexthop(znh, nh);
+ if (ret == 0)
+ UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
+
+ return ret;
+}
+
+/*
* Decode the nexthop-tracking update message
*/
bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
@@ -1521,33 +1635,34 @@ int zebra_redistribute_default_send(int command, struct zclient *zclient,
}
/* Get prefix in ZServ format; family should be filled in on prefix */
-static void zclient_stream_get_prefix(struct stream *s, struct prefix *p)
+static int zclient_stream_get_prefix(struct stream *s, struct prefix *p)
{
size_t plen = prefix_blen(p);
uint8_t c;
p->prefixlen = 0;
if (plen == 0)
- return;
+ return -1;
- stream_get(&p->u.prefix, s, plen);
+ STREAM_GET(&p->u.prefix, s, plen);
STREAM_GETC(s, c);
p->prefixlen = MIN(plen * 8, c);
+ return 0;
stream_failure:
- return;
+ return -1;
}
/* Router-id update from zebra daemon. */
-void zebra_router_id_update_read(struct stream *s, struct prefix *rid)
+int zebra_router_id_update_read(struct stream *s, struct prefix *rid)
{
/* Fetch interface address. */
STREAM_GETC(s, rid->family);
- zclient_stream_get_prefix(s, rid);
+ return zclient_stream_get_prefix(s, rid);
stream_failure:
- return;
+ return -1;
}
/* Interface addition from zebra daemon. */
@@ -1596,24 +1711,36 @@ stream_failure:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-static void zclient_vrf_add(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_vrf_add(struct zclient *zclient, vrf_id_t vrf_id)
{
struct vrf *vrf;
- char vrfname_tmp[VRF_NAMSIZ];
+ char vrfname_tmp[VRF_NAMSIZ + 1] = {};
struct vrf_data data;
- stream_get(&data, zclient->ibuf, sizeof(struct vrf_data));
+ STREAM_GET(&data, zclient->ibuf, sizeof(struct vrf_data));
/* Read interface name. */
- stream_get(vrfname_tmp, zclient->ibuf, VRF_NAMSIZ);
+ STREAM_GET(vrfname_tmp, zclient->ibuf, VRF_NAMSIZ);
+
+ if (strlen(vrfname_tmp) == 0)
+ goto stream_failure;
- /* Lookup/create vrf by vrf_id. */
+ /* Lookup/create vrf by name, then vrf_id. */
vrf = vrf_get(vrf_id, vrfname_tmp);
+
+ /* If there's already a VRF with this name, don't create vrf */
+ if (!vrf)
+ return 0;
+
vrf->data.l.table_id = data.l.table_id;
memcpy(vrf->data.l.netns_name, data.l.netns_name, NS_NAMSIZ);
/* overwrite default vrf */
if (vrf_id == VRF_DEFAULT)
vrf_set_default_name(vrfname_tmp, false);
vrf_enable(vrf);
+
+ return 0;
+stream_failure:
+ return -1;
}
static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
@@ -1634,21 +1761,32 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
vrf_delete(vrf);
}
-static void zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
{
struct interface *ifp;
- char ifname_tmp[INTERFACE_NAMSIZ];
+ char ifname_tmp[INTERFACE_NAMSIZ + 1] = {};
struct stream *s = zclient->ibuf;
/* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
+ STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ);
/* Lookup/create interface by name. */
+ if (!vrf_get(vrf_id, NULL)) {
+ zlog_debug(
+ "Rx'd interface add from Zebra, but VRF %u does not exist",
+ vrf_id);
+ return -1;
+ }
+
ifp = if_get_by_name(ifname_tmp, vrf_id);
zebra_interface_if_set_value(s, ifp);
if_new_via_zapi(ifp);
+
+ return 0;
+stream_failure:
+ return -1;
}
/*
@@ -1660,10 +1798,10 @@ static void zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
{
struct interface *ifp;
- char ifname_tmp[INTERFACE_NAMSIZ];
+ char ifname_tmp[INTERFACE_NAMSIZ + 1] = {};
/* Read interface name. */
- stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
+ STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ);
/* Lookup this by interface index. */
ifp = if_lookup_by_name(ifname_tmp, vrf_id);
@@ -1677,6 +1815,8 @@ struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id)
zebra_interface_if_set_value(s, ifp);
return ifp;
+stream_failure:
+ return NULL;
}
static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id)
@@ -1730,21 +1870,23 @@ static void zclient_handle_error(ZAPI_CALLBACK_ARGS)
(*zclient->handle_error)(error);
}
-static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
+static int link_params_set_value(struct stream *s, struct if_link_params *iflp)
{
if (iflp == NULL)
- return;
+ return -1;
- iflp->lp_status = stream_getl(s);
- iflp->te_metric = stream_getl(s);
- iflp->max_bw = stream_getf(s);
- iflp->max_rsv_bw = stream_getf(s);
- uint32_t bwclassnum = stream_getl(s);
+ uint32_t bwclassnum;
+
+ STREAM_GETL(s, iflp->lp_status);
+ STREAM_GETL(s, iflp->te_metric);
+ STREAM_GETF(s, iflp->max_bw);
+ STREAM_GETF(s, iflp->max_rsv_bw);
+ STREAM_GETL(s, bwclassnum);
{
unsigned int i;
for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++)
- iflp->unrsv_bw[i] = stream_getf(s);
+ STREAM_GETF(s, iflp->unrsv_bw[i]);
if (i < bwclassnum)
flog_err(
EC_LIB_ZAPI_MISSMATCH,
@@ -1752,19 +1894,23 @@ static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
" - outdated library?",
__func__, bwclassnum, MAX_CLASS_TYPE);
}
- iflp->admin_grp = stream_getl(s);
- iflp->rmt_as = stream_getl(s);
+ STREAM_GETL(s, iflp->admin_grp);
+ STREAM_GETL(s, iflp->rmt_as);
iflp->rmt_ip.s_addr = stream_get_ipv4(s);
- iflp->av_delay = stream_getl(s);
- iflp->min_delay = stream_getl(s);
- iflp->max_delay = stream_getl(s);
- iflp->delay_var = stream_getl(s);
+ STREAM_GETL(s, iflp->av_delay);
+ STREAM_GETL(s, iflp->min_delay);
+ STREAM_GETL(s, iflp->max_delay);
+ STREAM_GETL(s, iflp->delay_var);
+
+ STREAM_GETF(s, iflp->pkt_loss);
+ STREAM_GETF(s, iflp->res_bw);
+ STREAM_GETF(s, iflp->ava_bw);
+ STREAM_GETF(s, iflp->use_bw);
- iflp->pkt_loss = stream_getf(s);
- iflp->res_bw = stream_getf(s);
- iflp->ava_bw = stream_getf(s);
- iflp->use_bw = stream_getf(s);
+ return 0;
+stream_failure:
+ return -1;
}
struct interface *zebra_interface_link_params_read(struct stream *s,
@@ -1773,9 +1919,7 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
struct if_link_params *iflp;
ifindex_t ifindex;
- assert(s);
-
- ifindex = stream_getl(s);
+ STREAM_GETL(s, ifindex);
struct interface *ifp = if_lookup_by_index(ifindex, vrf_id);
@@ -1789,36 +1933,41 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
if ((iflp = if_link_params_get(ifp)) == NULL)
return NULL;
- link_params_set_value(s, iflp);
+ if (link_params_set_value(s, iflp) != 0)
+ goto stream_failure;
return ifp;
+
+stream_failure:
+ return NULL;
}
static void zebra_interface_if_set_value(struct stream *s,
struct interface *ifp)
{
uint8_t link_params_status = 0;
- ifindex_t old_ifindex;
+ ifindex_t old_ifindex, new_ifindex;
old_ifindex = ifp->ifindex;
/* Read interface's index. */
- if_set_index(ifp, stream_getl(s));
- ifp->status = stream_getc(s);
+ STREAM_GETL(s, new_ifindex);
+ if_set_index(ifp, new_ifindex);
+ STREAM_GETC(s, ifp->status);
/* Read interface's value. */
- ifp->flags = stream_getq(s);
- ifp->ptm_enable = stream_getc(s);
- ifp->ptm_status = stream_getc(s);
- ifp->metric = stream_getl(s);
- ifp->speed = stream_getl(s);
- ifp->mtu = stream_getl(s);
- ifp->mtu6 = stream_getl(s);
- ifp->bandwidth = stream_getl(s);
- ifp->link_ifindex = stream_getl(s);
- ifp->ll_type = stream_getl(s);
- ifp->hw_addr_len = stream_getl(s);
+ STREAM_GETQ(s, ifp->flags);
+ STREAM_GETC(s, ifp->ptm_enable);
+ STREAM_GETC(s, ifp->ptm_status);
+ STREAM_GETL(s, ifp->metric);
+ STREAM_GETL(s, ifp->speed);
+ STREAM_GETL(s, ifp->mtu);
+ STREAM_GETL(s, ifp->mtu6);
+ STREAM_GETL(s, ifp->bandwidth);
+ STREAM_GETL(s, ifp->link_ifindex);
+ STREAM_GETL(s, ifp->ll_type);
+ STREAM_GETL(s, ifp->hw_addr_len);
if (ifp->hw_addr_len)
- stream_get(ifp->hw_addr, s,
+ STREAM_GET(ifp->hw_addr, s,
MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
/* Read Traffic Engineering status */
@@ -1830,6 +1979,11 @@ static void zebra_interface_if_set_value(struct stream *s,
}
nexthop_group_interface_state_change(ifp, old_ifindex);
+
+ return;
+stream_failure:
+ zlog_err("Could not parse interface values; aborting");
+ assert(!"Failed to parse interface values");
}
size_t zebra_interface_link_params_write(struct stream *s,
@@ -1928,7 +2082,7 @@ struct connected *zebra_interface_address_read(int type, struct stream *s,
memset(&d, 0, sizeof(d));
/* Get interface index. */
- ifindex = stream_getl(s);
+ STREAM_GETL(s, ifindex);
/* Lookup index. */
ifp = if_lookup_by_index(ifindex, vrf_id);
@@ -1941,16 +2095,18 @@ struct connected *zebra_interface_address_read(int type, struct stream *s,
}
/* Fetch flag. */
- ifc_flags = stream_getc(s);
+ STREAM_GETC(s, ifc_flags);
/* Fetch interface address. */
- d.family = p.family = stream_getc(s);
+ STREAM_GETC(s, d.family);
+ p.family = d.family;
plen = prefix_blen(&d);
- zclient_stream_get_prefix(s, &p);
+ if (zclient_stream_get_prefix(s, &p) != 0)
+ goto stream_failure;
/* Fetch destination address. */
- stream_get(&d.u.prefix, s, plen);
+ STREAM_GET(&d.u.prefix, s, plen);
/* N.B. NULL destination pointers are encoded as all zeroes */
dp = memconstant(&d.u.prefix, 0, plen) ? NULL : &d;
@@ -1986,6 +2142,9 @@ struct connected *zebra_interface_address_read(int type, struct stream *s,
}
return ifc;
+
+stream_failure:
+ return NULL;
}
/*
@@ -2021,7 +2180,7 @@ zebra_interface_nbr_address_read(int type, struct stream *s, vrf_id_t vrf_id)
struct nbr_connected *ifc;
/* Get interface index. */
- ifindex = stream_getl(s);
+ STREAM_GETL(s, ifindex);
/* Lookup index. */
ifp = if_lookup_by_index(ifindex, vrf_id);
@@ -2034,9 +2193,9 @@ zebra_interface_nbr_address_read(int type, struct stream *s, vrf_id_t vrf_id)
return NULL;
}
- p.family = stream_getc(s);
- stream_get(&p.u.prefix, s, prefix_blen(&p));
- p.prefixlen = stream_getc(s);
+ STREAM_GETC(s, p.family);
+ STREAM_GET(&p.u.prefix, s, prefix_blen(&p));
+ STREAM_GETC(s, p.prefixlen);
if (type == ZEBRA_INTERFACE_NBR_ADDRESS_ADD) {
/* Currently only supporting P2P links, so any new RA source
@@ -2060,18 +2219,21 @@ zebra_interface_nbr_address_read(int type, struct stream *s, vrf_id_t vrf_id)
}
return ifc;
+
+stream_failure:
+ return NULL;
}
struct interface *zebra_interface_vrf_update_read(struct stream *s,
vrf_id_t vrf_id,
vrf_id_t *new_vrf_id)
{
- char ifname[INTERFACE_NAMSIZ];
+ char ifname[INTERFACE_NAMSIZ + 1] = {};
struct interface *ifp;
vrf_id_t new_id;
/* Read interface name. */
- stream_get(ifname, s, INTERFACE_NAMSIZ);
+ STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
/* Lookup interface. */
ifp = if_lookup_by_name(ifname, vrf_id);
@@ -2083,10 +2245,13 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s,
}
/* Fetch new VRF Id. */
- new_id = stream_getl(s);
+ STREAM_GETL(s, new_id);
*new_vrf_id = new_id;
return ifp;
+
+stream_failure:
+ return NULL;
}
/* filter unwanted messages until the expected one arrives */
@@ -2195,8 +2360,11 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
s = zclient->ibuf;
/* read instance and proto */
- uint8_t proto = stream_getc(s);
- uint16_t instance = stream_getw(s);
+ uint8_t proto;
+ uint16_t instance;
+
+ STREAM_GETC(s, proto);
+ STREAM_GETW(s, instance);
/* sanity */
if (proto != zclient->redist_default)
@@ -2211,11 +2379,14 @@ int lm_label_manager_connect(struct zclient *zclient, int async)
instance, zclient->instance);
/* result code */
- result = stream_getc(s);
+ STREAM_GETC(s, result);
if (zclient_debug)
zlog_debug("LM connect-response received, result %u", result);
return (int)result;
+
+stream_failure:
+ return -1;
}
/*
@@ -2323,8 +2494,11 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
s = zclient->ibuf;
/* read proto and instance */
- uint8_t proto = stream_getc(s);
- uint16_t instance = stream_getw(s);
+ uint8_t proto;
+ uint8_t instance;
+
+ STREAM_GETC(s, proto);
+ STREAM_GETW(s, instance);
/* sanities */
if (proto != zclient->redist_default)
@@ -2346,10 +2520,10 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
}
/* keep */
- response_keep = stream_getc(s);
+ STREAM_GETC(s, response_keep);
/* start and end labels */
- *start = stream_getl(s);
- *end = stream_getl(s);
+ STREAM_GETL(s, *start);
+ STREAM_GETL(s, *end);
/* not owning this response */
if (keep != response_keep) {
@@ -2371,6 +2545,9 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t base,
response_keep);
return 0;
+
+stream_failure:
+ return -1;
}
/**
@@ -2760,7 +2937,7 @@ int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
/*
* Receive PW status update from Zebra and send it to LDE process.
*/
-void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw)
+int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw)
{
struct stream *s;
@@ -2769,8 +2946,12 @@ void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw)
/* Get data. */
stream_get(pw->ifname, s, IF_NAMESIZE);
- pw->ifindex = stream_getl(s);
- pw->status = stream_getl(s);
+ STREAM_GETL(s, pw->ifindex);
+ STREAM_GETL(s, pw->status);
+
+ return 0;
+stream_failure:
+ return -1;
}
static void zclient_capability_decode(ZAPI_CALLBACK_ARGS)
@@ -2781,7 +2962,14 @@ static void zclient_capability_decode(ZAPI_CALLBACK_ARGS)
uint8_t mpls_enabled;
STREAM_GETL(s, vrf_backend);
- vrf_configure_backend(vrf_backend);
+
+ if (vrf_backend < 0 || vrf_configure_backend(vrf_backend)) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: Garbage VRF backend type: %d\n", __func__,
+ vrf_backend);
+ goto stream_failure;
+ }
+
memset(&cap, 0, sizeof(cap));
STREAM_GETC(s, mpls_enabled);
diff --git a/lib/zclient.h b/lib/zclient.h
index e6f4c747e3..214226cf5f 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -255,6 +255,9 @@ struct zclient {
/* Do we care about failure events for route install? */
bool receive_notify;
+ /* Is this a synchronous client? */
+ bool synchronous;
+
/* Socket to zebra daemon. */
int sock;
@@ -338,6 +341,9 @@ struct zclient {
#define ZAPI_MESSAGE_TAG 0x08
#define ZAPI_MESSAGE_MTU 0x10
#define ZAPI_MESSAGE_SRCPFX 0x20
+/* Backup nexthops are present */
+#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
+
/*
* This should only be used by a DAEMON that needs to communicate
* the table being used is not in the VRF. You must pass the
@@ -374,14 +380,21 @@ struct zapi_nexthop {
struct ethaddr rmac;
uint32_t weight;
+
+ /* Index of backup nexthop */
+ uint8_t backup_idx;
};
/*
- * ZAPI nexthop flags values
+ * ZAPI nexthop flags values - we're encoding a single octet
+ * initially, so ensure that the on-the-wire encoding continues
+ * to match the number of valid flags.
*/
+
#define ZAPI_NEXTHOP_FLAG_ONLINK 0x01
#define ZAPI_NEXTHOP_FLAG_LABEL 0x02
#define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04
+#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */
/*
* Some of these data structures do not map easily to
@@ -445,6 +458,10 @@ struct zapi_route {
uint16_t nexthop_num;
struct zapi_nexthop nexthops[MULTIPATH_NUM];
+ /* Support backup routes for IP FRR, TI-LFA, traffic engineering */
+ uint16_t backup_nexthop_num;
+ struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+
uint8_t distance;
uint32_t metric;
@@ -569,6 +586,7 @@ enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
struct zclient_options {
bool receive_notify;
+ bool synchronous;
};
extern struct zclient_options zclient_options_default;
@@ -705,7 +723,7 @@ zebra_interface_nbr_address_read(int, struct stream *, vrf_id_t);
extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
vrf_id_t vrf_id,
vrf_id_t *new_vrf_id);
-extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
+extern int zebra_router_id_update_read(struct stream *s, struct prefix *rid);
extern struct interface *zebra_interface_link_params_read(struct stream *s,
vrf_id_t vrf_id);
@@ -734,11 +752,12 @@ extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
extern int zebra_send_pw(struct zclient *zclient, int command,
struct zapi_pw *pw);
-extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw);
+extern int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS,
+ struct zapi_pw_status *pw);
extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *);
extern int zclient_send_rnh(struct zclient *zclient, int command,
- struct prefix *p, bool exact_match,
+ const struct prefix *p, bool exact_match,
vrf_id_t vrf_id);
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
uint32_t api_flags);
@@ -765,9 +784,12 @@ bool zapi_iptable_notify_decode(struct stream *s,
uint32_t *unique,
enum zapi_iptable_notify_owner *note);
-extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
+extern struct nexthop *
+nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh);
int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
const struct nexthop *nh);
+int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh);
extern bool zapi_nexthop_update_decode(struct stream *s,
struct zapi_route *nhr);
@@ -796,4 +818,9 @@ extern void zclient_send_mlag_deregister(struct zclient *client);
extern void zclient_send_mlag_data(struct zclient *client,
struct stream *client_s);
+/* Send the hello message.
+ * Returns 0 for success or -1 on an I/O error.
+ */
+extern int zclient_send_hello(struct zclient *client);
+
#endif /* _ZEBRA_ZCLIENT_H */