diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/agg_table.h | 10 | ||||
| -rw-r--r-- | lib/compiler.h | 9 | ||||
| -rw-r--r-- | lib/frrlua.c | 2 | ||||
| -rw-r--r-- | lib/frrlua.h | 2 | ||||
| -rw-r--r-- | lib/grammar_sandbox_main.c | 2 | ||||
| -rw-r--r-- | lib/ipaddr.h | 2 | ||||
| -rw-r--r-- | lib/log.c | 88 | ||||
| -rw-r--r-- | lib/log.h | 2 | ||||
| -rw-r--r-- | lib/mpls.c | 2 | ||||
| -rw-r--r-- | lib/mpls.h | 5 | ||||
| -rw-r--r-- | lib/nexthop.c | 50 | ||||
| -rw-r--r-- | lib/nexthop.h | 26 | ||||
| -rw-r--r-- | lib/nexthop_group.c | 94 | ||||
| -rw-r--r-- | lib/nexthop_group.h | 9 | ||||
| -rw-r--r-- | lib/northbound_grpc.cpp | 21 | ||||
| -rw-r--r-- | lib/plist.c | 2 | ||||
| -rw-r--r-- | lib/prefix.h | 18 | ||||
| -rw-r--r-- | lib/printfrr.h | 14 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 38 | ||||
| -rw-r--r-- | lib/skiplist.c | 11 | ||||
| -rw-r--r-- | lib/skiplist.h | 13 | ||||
| -rw-r--r-- | lib/smux.h | 2 | ||||
| -rw-r--r-- | lib/snmp.c | 4 | ||||
| -rw-r--r-- | lib/spf_backoff.c | 2 | ||||
| -rw-r--r-- | lib/spf_backoff.h | 2 | ||||
| -rw-r--r-- | lib/srcdest_table.c | 2 | ||||
| -rw-r--r-- | lib/srcdest_table.h | 2 | ||||
| -rw-r--r-- | lib/stream.c | 2 | ||||
| -rw-r--r-- | lib/stream.h | 5 | ||||
| -rw-r--r-- | lib/table.h | 4 | ||||
| -rw-r--r-- | lib/thread.c | 9 | ||||
| -rw-r--r-- | lib/vty.c | 9 | ||||
| -rw-r--r-- | lib/yang_wrappers.c | 5 | ||||
| -rw-r--r-- | lib/zclient.c | 128 | ||||
| -rw-r--r-- | lib/zclient.h | 32 |
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)); @@ -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) @@ -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(©->gate, &nexthop->gate, sizeof(nexthop->gate)); memcpy(©->src, &nexthop->src, sizeof(nexthop->src)); memcpy(©->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' : ' ', @@ -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 */ |
