summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agg_table.h10
-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.c2
-rw-r--r--lib/ipaddr.h2
-rw-r--r--lib/log.c88
-rw-r--r--lib/log.h2
-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.c94
-rw-r--r--lib/nexthop_group.h9
-rw-r--r--lib/northbound_grpc.cpp21
-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/skiplist.c11
-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.c2
-rw-r--r--lib/stream.h5
-rw-r--r--lib/table.h4
-rw-r--r--lib/thread.c9
-rw-r--r--lib/vty.c9
-rw-r--r--lib/yang_wrappers.c5
-rw-r--r--lib/zclient.c128
-rw-r--r--lib/zclient.h32
35 files changed, 492 insertions, 136 deletions
diff --git a/lib/agg_table.h b/lib/agg_table.h
index f95fed6758..e98476f1b7 100644
--- a/lib/agg_table.h
+++ b/lib/agg_table.h
@@ -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/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..5d3f6675a3 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
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/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/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..8c3bbbdcd4 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,
@@ -225,6 +229,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);
@@ -567,11 +575,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,6 +621,8 @@ 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);
}
@@ -629,7 +664,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 +723,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 +743,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 +756,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 +769,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 add_update = false;
+
+ 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)) {
@@ -765,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nh = nexthop_exists(&nhgc->nhg, &nhop);
- if (no) {
+ if (no || nh) {
+ /* Remove or replace cases */
+
+ /* Remove existing config */
nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
weight);
if (nh) {
+ /* Remove nexthop object */
_nexthop_del(&nhgc->nhg, nh);
if (nhg_hooks.del_nexthop)
nhg_hooks.del_nexthop(nhgc, nh);
nexthop_free(nh);
+ nh = NULL;
}
- } else if (!nh) {
- /* must be adding new nexthop since !no and !nexthop_exists */
+ }
+
+ add_update = !no;
+
+ if (add_update) {
+ /* Add or replace cases */
+
+ /* If valid config, add nexthop object */
if (legal) {
nh = nexthop_new();
@@ -785,8 +848,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 +913,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 +941,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 +957,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 +1141,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_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/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/skiplist.c b/lib/skiplist.c
index d955c6eb9e..fa25770efa 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 */
{
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..f046572f41 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -898,7 +898,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..6fcf9a53cf 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);
@@ -354,9 +354,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;
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/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_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..d380267a70 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;
}
@@ -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)
diff --git a/lib/zclient.h b/lib/zclient.h
index e6f4c747e3..e747809f16 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;
@@ -738,7 +756,7 @@ extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_statu
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 +783,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 +817,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 */