summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/bfd.c27
-rw-r--r--lib/bfd.h4
-rw-r--r--lib/command.h12
-rw-r--r--lib/libfrr.c10
-rw-r--r--lib/nexthop.c127
-rw-r--r--lib/nexthop.h25
-rw-r--r--lib/nexthop_group.c81
-rw-r--r--lib/nexthop_group.h6
-rw-r--r--lib/pbr.h7
-rwxr-xr-xlib/route_types.pl2
-rw-r--r--lib/stream.c14
-rw-r--r--lib/subdir.am3
-rw-r--r--lib/vrf.c6
-rw-r--r--lib/zclient.c37
-rw-r--r--lib/zclient.h5
-rw-r--r--lib/zlog.c6
16 files changed, 273 insertions, 99 deletions
diff --git a/lib/bfd.c b/lib/bfd.c
index 6173ebc197..d1a0ec671e 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -94,7 +94,8 @@ int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str,
* bfd_set_param - Set the configured BFD paramter values
*/
void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
- uint8_t detect_mult, int defaults, int *command)
+ uint8_t detect_mult, const char *profile, int defaults,
+ int *command)
{
if (!*bfd_info) {
*bfd_info = bfd_info_create();
@@ -102,7 +103,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
} else {
if (((*bfd_info)->required_min_rx != min_rx)
|| ((*bfd_info)->desired_min_tx != min_tx)
- || ((*bfd_info)->detect_mult != detect_mult))
+ || ((*bfd_info)->detect_mult != detect_mult)
+ || (profile && strcmp((*bfd_info)->profile, profile)))
*command = ZEBRA_BFD_DEST_UPDATE;
}
@@ -110,6 +112,11 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
(*bfd_info)->required_min_rx = min_rx;
(*bfd_info)->desired_min_tx = min_tx;
(*bfd_info)->detect_mult = detect_mult;
+ if (profile)
+ strlcpy((*bfd_info)->profile, profile,
+ BFD_PROFILE_NAME_LEN);
+ else
+ (*bfd_info)->profile[0] = '\0';
}
if (!defaults)
@@ -121,6 +128,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
/*
* bfd_peer_sendmsg - Format and send a peer register/Unregister
* command to Zebra to be forwarded to BFD
+ *
+ * DEPRECATED: use zclient_bfd_command instead
*/
void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip, char *if_name,
@@ -161,6 +170,11 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
args.min_rx = bfd_info->required_min_rx;
args.min_tx = bfd_info->desired_min_tx;
args.detection_multiplier = bfd_info->detect_mult;
+ if (bfd_info->profile[0]) {
+ args.profilelen = strlen(bfd_info->profile);
+ strlcpy(args.profile, bfd_info->profile,
+ sizeof(args.profile));
+ }
}
addrlen = family == AF_INET ? sizeof(struct in_addr)
@@ -425,6 +439,15 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
struct stream *s;
size_t addrlen;
+ /* Individual reg/dereg messages are suppressed during shutdown. */
+ if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
+ if (bfd_debug)
+ zlog_debug(
+ "%s: Suppressing BFD peer reg/dereg messages",
+ __func__);
+ return -1;
+ }
+
/* Check socket. */
if (!zc || zc->sock < 0) {
if (bfd_debug)
diff --git a/lib/bfd.h b/lib/bfd.h
index d7d4b5fe35..ceab4628b6 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -92,8 +92,8 @@ extern int bfd_validate_param(struct vty *vty, const char *dm_str,
uint32_t *tx_val);
extern void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult, int defaults,
- int *command);
+ uint32_t min_tx, uint8_t detect_mult,
+ const char *profile, int defaults, int *command);
extern void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip,
char *if_name, int ttl, int multihop, int cbit,
diff --git a/lib/command.h b/lib/command.h
index 21bb613540..1acca90665 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -328,18 +328,6 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \
CMD_ATTR_DEPRECATED, daemon)
-#else /* VTYSH_EXTRACT_PL */
-#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
- DEFUN(funcname, cmdname, cmdstr, helpstr)
-
-#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr)
-
-#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
- DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr)
-
-#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr)
#endif /* VTYSH_EXTRACT_PL */
/* Some macroes */
diff --git a/lib/libfrr.c b/lib/libfrr.c
index b3df7de6d3..2597eb61e2 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -105,6 +105,7 @@ static const struct option lo_always[] = {
{"daemon", no_argument, NULL, 'd'},
{"module", no_argument, NULL, 'M'},
{"profile", required_argument, NULL, 'F'},
+ {"pathspace", required_argument, NULL, 'N'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
{"log", required_argument, NULL, OPTION_LOG},
@@ -113,12 +114,13 @@ static const struct option lo_always[] = {
{"command-log-always", no_argument, NULL, OPTION_LOGGING},
{NULL}};
static const struct optspec os_always = {
- "hvdM:F:",
+ "hvdM:F:N:",
" -h, --help Display this help and exit\n"
" -v, --version Print program version\n"
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
" -F, --profile Use specified configuration profile\n"
+ " -N, --pathspace Insert prefix into config & socket paths\n"
" --vty_socket Override vty socket path\n"
" --moduledir Override modules directory\n"
" --log Set Logging to stdout, syslog, or file:<name>\n"
@@ -133,18 +135,16 @@ static const struct option lo_cfg_pid_dry[] = {
#ifdef HAVE_SQLITE3
{"db_file", required_argument, NULL, OPTION_DB_FILE},
#endif
- {"pathspace", required_argument, NULL, 'N'},
{"dryrun", no_argument, NULL, 'C'},
{"terminal", no_argument, NULL, 't'},
{NULL}};
static const struct optspec os_cfg_pid_dry = {
- "f:i:CtN:",
+ "f:i:Ct",
" -f, --config_file Set configuration file name\n"
" -i, --pid_file Set process identifier file name\n"
#ifdef HAVE_SQLITE3
" --db_file Set database file name\n"
#endif
- " -N, --pathspace Insert prefix into config & socket paths\n"
" -C, --dryrun Check configuration for validity and exit\n"
" -t, --terminal Open terminal session on stdio\n"
" -d -t Daemonize after terminal session ends\n",
@@ -428,8 +428,6 @@ static int frr_opt(int opt)
di->config_file = optarg;
break;
case 'N':
- if (di->flags & FRR_NO_CFG_PID_DRY)
- return 1;
if (di->pathspace) {
fprintf(stderr,
"-N/--pathspace option specified more than once!\n");
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 3496081d47..28d96a539c 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -157,6 +157,10 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
goto done;
if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 0;
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
return -1;
@@ -164,12 +168,18 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
!CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
return 1;
- if (next1->backup_idx < next2->backup_idx)
+ if (next1->backup_num == 0 && next2->backup_num == 0)
+ goto done;
+
+ if (next1->backup_num < next2->backup_num)
return -1;
- if (next1->backup_idx > next2->backup_idx)
+ if (next1->backup_num > next2->backup_num)
return 1;
+ ret = memcmp(next1->backup_idx,
+ next2->backup_idx, next1->backup_num);
+
done:
return ret;
}
@@ -515,11 +525,12 @@ struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
return next;
}
-unsigned int nexthop_level(struct nexthop *nexthop)
+unsigned int nexthop_level(const struct nexthop *nexthop)
{
unsigned int rv = 0;
- for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
+ for (const struct nexthop *par = nexthop->rparent;
+ par; par = par->rparent)
rv++;
return rv;
@@ -529,14 +540,15 @@ unsigned int nexthop_level(struct nexthop *nexthop)
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
- uint32_t val;
+ int i;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
if (nexthop->nh_label) {
int labels = nexthop->nh_label->num_labels;
- int i = 0;
+
+ i = 0;
while (labels >= 3) {
key = jhash_3words(nexthop->nh_label->label[i],
@@ -559,14 +571,35 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- 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 = jhash_2words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
key);
+ /* Include backup nexthops, if present */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ int backups = nexthop->backup_num;
+
+ i = 0;
+
+ while (backups >= 3) {
+ key = jhash_3words(nexthop->backup_idx[i],
+ nexthop->backup_idx[i + 1],
+ nexthop->backup_idx[i + 2], key);
+ backups -= 3;
+ i += 3;
+ }
+
+ while (backups >= 2) {
+ key = jhash_2words(nexthop->backup_idx[i],
+ nexthop->backup_idx[i + 1], key);
+ backups -= 2;
+ i += 2;
+ }
+
+ if (backups >= 1)
+ key = jhash_1word(nexthop->backup_idx[i], key);
+ }
+
return key;
}
@@ -604,7 +637,12 @@ 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;
+
+ assert(nexthop->backup_num < NEXTHOP_MAX_BACKUPS);
+ copy->backup_num = nexthop->backup_num;
+ if (copy->backup_num > 0)
+ memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num);
+
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));
@@ -621,7 +659,7 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
nexthop_copy_no_recurse(copy, nexthop, rparent);
/* Bit of a special case here, we need to handle the case
- * of a nexthop resolving to agroup. Hence, we need to
+ * of a nexthop resolving to a group. Hence, we need to
* use a nexthop_group API.
*/
if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -647,6 +685,67 @@ struct nexthop *nexthop_dup(const struct nexthop *nexthop,
}
/*
+ * Parse one or more backup index values, as comma-separated numbers,
+ * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS
+ * in size. Mails back the number of values converted, and returns 0 on
+ * success, <0 if an error in parsing.
+ */
+int nexthop_str2backups(const char *str, int *num_backups,
+ uint8_t *backups)
+{
+ char *ostr; /* copy of string (start) */
+ char *lstr; /* working copy of string */
+ char *nump; /* pointer to next segment */
+ char *endp; /* end pointer */
+ int i, ret;
+ uint8_t tmp[NEXTHOP_MAX_BACKUPS];
+ uint32_t lval;
+
+ /* Copy incoming string; the parse is destructive */
+ lstr = ostr = XSTRDUP(MTYPE_TMP, str);
+ *num_backups = 0;
+ ret = 0;
+
+ for (i = 0; i < NEXTHOP_MAX_BACKUPS && lstr; i++) {
+ nump = strsep(&lstr, ",");
+ lval = strtoul(nump, &endp, 10);
+
+ /* Format check */
+ if (*endp != '\0') {
+ ret = -1;
+ break;
+ }
+
+ /* Empty value */
+ if (endp == nump) {
+ ret = -1;
+ break;
+ }
+
+ /* Limit to one octet */
+ if (lval > 255) {
+ ret = -1;
+ break;
+ }
+
+ tmp[i] = lval;
+ }
+
+ /* Excess values */
+ if (ret == 0 && i == NEXTHOP_MAX_BACKUPS && lstr)
+ ret = -1;
+
+ if (ret == 0) {
+ *num_backups = i;
+ memcpy(backups, tmp, i);
+ }
+
+ XFREE(MTYPE_TMP, ostr);
+
+ return ret;
+}
+
+/*
* nexthop printing variants:
* %pNHvv
* via 1.2.3.4
diff --git a/lib/nexthop.h b/lib/nexthop.h
index eda88efc08..ed40cc7eed 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -65,6 +65,12 @@ enum nh_encap_type {
NET_VXLAN = 100, /* value copied from FPM_NH_ENCAP_VXLAN. */
};
+/* Fixed limit on the number of backup nexthops per primary nexthop */
+#define NEXTHOP_MAX_BACKUPS 8
+
+/* Backup index value is limited */
+#define NEXTHOP_BACKUP_IDX_MAX 255
+
/* Nexthop structure. */
struct nexthop {
struct nexthop *next;
@@ -124,10 +130,11 @@ struct nexthop {
/* Weight of the nexthop ( for unequal cost ECMP ) */
uint8_t weight;
- /* Index of a corresponding backup nexthop in a backup list;
+ /* Count and index of corresponding backup nexthop(s) in a backup list;
* only meaningful if the HAS_BACKUP flag is set.
*/
- uint8_t backup_idx;
+ uint8_t backup_num;
+ uint8_t backup_idx[NEXTHOP_MAX_BACKUPS];
/* Encapsulation information. */
enum nh_encap_type nh_encap_type;
@@ -136,9 +143,6 @@ struct nexthop {
} nh_encap;
};
-/* Backup index value is limited */
-#define NEXTHOP_BACKUP_IDX_MAX 255
-
/* Utility to append one nexthop to another. */
#define NEXTHOP_APPEND(to, new) \
do { \
@@ -216,7 +220,7 @@ extern const char *nexthop2str(const struct nexthop *nexthop,
extern struct nexthop *nexthop_next(const struct nexthop *nexthop);
extern struct nexthop *
nexthop_next_active_resolved(const struct nexthop *nexthop);
-extern unsigned int nexthop_level(struct nexthop *nexthop);
+extern unsigned int nexthop_level(const struct nexthop *nexthop);
/* Copies to an already allocated nexthop struct */
extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
struct nexthop *rparent);
@@ -231,6 +235,15 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop,
extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
struct nexthop *rparent);
+/*
+ * Parse one or more backup index values, as comma-separated numbers,
+ * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS
+ * in size. Mails back the number of values converted, and returns 0 on
+ * success, <0 if an error in parsing.
+ */
+int nexthop_str2backups(const char *str, int *num_backups,
+ uint8_t *backups);
+
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pNH" (struct nexthop *)
#endif
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 4f0c72af27..97815ceeb9 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -43,12 +43,9 @@ struct nexthop_hold {
char *intf;
char *labels;
uint32_t weight;
- int backup_idx; /* Index of backup nexthop, if >= 0 */
+ char *backup_str;
};
-/* 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,
@@ -677,7 +674,8 @@ 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, int backup_idx)
+ const uint32_t weight,
+ const char *backup_str)
{
struct nexthop_hold *nh;
@@ -694,7 +692,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->weight = weight;
- nh->backup_idx = backup_idx;
+ if (backup_str)
+ nh->backup_str = XSTRDUP(MTYPE_TMP, backup_str);
listnode_add_sort(nhgc->nhg_list, nh);
}
@@ -741,10 +740,11 @@ 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, int backup_idx)
+ uint32_t weight, const char *backup_str)
{
int ret = 0;
struct vrf *vrf;
+ int num;
memset(nhop, 0, sizeof(*nhop));
@@ -800,13 +800,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)
+ if (backup_str) {
+ /* Parse backup indexes */
+ ret = nexthop_str2backups(backup_str,
+ &num, nhop->backup_idx);
+ if (ret == 0) {
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nhop->backup_num = num;
+ } else
return false;
-
- SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
- nhop->backup_idx = backup_idx;
}
return true;
@@ -820,7 +822,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->backup_idx));
+ nhh->weight, nhh->backup_str));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -833,7 +835,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nexthop-vrf NAME$vrf_name \
|label WORD \
|weight (1-255) \
- |backup-idx$bi_str (0-254)$idx \
+ |backup-idx WORD \
}]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
@@ -847,19 +849,26 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"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"
- "Backup nexthop index in another group\n"
- "Nexthop index value\n")
+ "Specify backup nexthop indexes in another group\n"
+ "One or more indexes in the range (0-254) separated by ','\n")
{
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct nexthop nhop;
struct nexthop *nh;
int lbl_ret = 0;
bool legal;
- int backup_idx = idx;
+ int num;
+ uint8_t backups[NEXTHOP_MAX_BACKUPS];
bool yes = !no;
- if (bi_str == NULL)
- backup_idx = NHH_BACKUP_IDX_INVALID;
+ /* Pre-parse backup string to validate */
+ if (backup_idx) {
+ lbl_ret = nexthop_str2backups(backup_idx, &num, backups);
+ if (lbl_ret < 0) {
+ vty_out(vty, "%% Invalid backups\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
&lbl_ret, weight, backup_idx);
@@ -943,10 +952,11 @@ static struct cmd_node nexthop_group_node = {
.config_write = nexthop_group_write,
};
-void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
+void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
{
char buf[100];
struct vrf *vrf;
+ int i;
vty_out(vty, "nexthop ");
@@ -991,16 +1001,22 @@ 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);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ vty_out(vty, " backup-idx %d", nh->backup_idx[0]);
+
+ for (i = 1; i < nh->backup_num; i++)
+ vty_out(vty, ",%d", nh->backup_idx[i]);
+ }
vty_out(vty, "\n");
}
-void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh)
+void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh)
{
char buf[100];
struct vrf *vrf;
+ json_object *json_backups = NULL;
+ int i;
switch (nh->type) {
case NEXTHOP_TYPE_IFINDEX:
@@ -1047,12 +1063,19 @@ void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh)
if (nh->weight)
json_object_int_add(j, "weight", nh->weight);
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
- json_object_int_add(j, "backupIdx", nh->backup_idx);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ json_backups = json_object_new_array();
+ for (i = 0; i < nh->backup_num; i++)
+ json_object_array_add(
+ json_backups,
+ json_object_new_int(nh->backup_idx[i]));
+
+ json_object_object_add(j, "backupIdx", json_backups);
+ }
}
static void nexthop_group_write_nexthop_internal(struct vty *vty,
- struct nexthop_hold *nh)
+ const struct nexthop_hold *nh)
{
char buf[100];
@@ -1073,8 +1096,8 @@ 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);
+ if (nh->backup_str)
+ vty_out(vty, " backup-idx %s", nh->backup_str);
vty_out(vty, "\n");
}
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 9888dad982..0b5ac91bb2 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -135,9 +135,11 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1,
extern struct nexthop_group_cmd *nhgc_find(const char *name);
-extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
+extern void nexthop_group_write_nexthop(struct vty *vty,
+ const struct nexthop *nh);
-extern void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh);
+extern void nexthop_group_json_nexthop(json_object *j,
+ const struct nexthop *nh);
/* Return the number of nexthops in this nhg */
extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
diff --git a/lib/pbr.h b/lib/pbr.h
index cf6ac41d32..fd183d7115 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -49,6 +49,10 @@ struct pbr_filter {
#define PBR_FILTER_PROTO (1 << 5)
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
+#define PBR_FILTER_DSFIELD (1 << 8)
+
+#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
+#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
/* Source and Destination IP address with masks. */
struct prefix src_ip;
@@ -58,6 +62,9 @@ struct pbr_filter {
uint16_t src_port;
uint16_t dst_port;
+ /* Filter by Differentiated Services field */
+ uint8_t dsfield; /* DSCP (6 bits) & ECN (2 bits) */
+
/* Filter with fwmark */
uint32_t fwmark;
};
diff --git a/lib/route_types.pl b/lib/route_types.pl
index f297096633..e007de4d69 100755
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -121,7 +121,7 @@ sub codelist {
}
$str =~ s/ $//;
push @lines, $str . "\\n\" \\\n";
- push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\"";
+ push @lines, " \" > - selected route, * - FIB route, q - queued, r - rejected, b - backup\\n\\n\"";
return join("", @lines);
}
diff --git a/lib/stream.c b/lib/stream.c
index 17520f978e..d3afebbf13 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -55,15 +55,19 @@ DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO")
* using stream_put..._at() functions.
*/
#define STREAM_WARN_OFFSETS(S) \
- flog_warn(EC_LIB_STREAM, \
- "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
- (void *)(S), (unsigned long)(S)->size, \
- (unsigned long)(S)->getp, (unsigned long)(S)->endp)
+ do { \
+ flog_warn(EC_LIB_STREAM, \
+ "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
+ (void *)(S), (unsigned long)(S)->size, \
+ (unsigned long)(S)->getp, (unsigned long)(S)->endp); \
+ zlog_backtrace(LOG_WARNING); \
+ } while (0)
#define STREAM_VERIFY_SANE(S) \
do { \
- if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) \
+ if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) { \
STREAM_WARN_OFFSETS(S); \
+ } \
assert(GETP_VALID(S, (S)->getp)); \
assert(ENDP_VALID(S, (S)->endp)); \
} while (0)
diff --git a/lib/subdir.am b/lib/subdir.am
index f185841c76..34ad30f968 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -124,9 +124,6 @@ nodist_lib_libfrr_la_SOURCES = \
yang/ietf/ietf-interfaces.yang.c \
yang/frr-module-translator.yang.c \
yang/frr-nexthop.yang.c \
- yang/frr-igmp.yang.c \
- yang/frr-pim.yang.c \
- yang/frr-pim-rp.yang.c \
# end
vtysh_scan += \
diff --git a/lib/vrf.c b/lib/vrf.c
index a9ea632ac5..a7a10451bf 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -757,10 +757,8 @@ DEFUN (no_vrf,
vrfp = vrf_lookup_by_name(vrfname);
- if (vrfp == NULL) {
- vty_out(vty, "%% VRF %s does not exist\n", vrfname);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (vrfp == NULL)
+ return CMD_SUCCESS;
if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) {
vty_out(vty, "%% Only inactive VRFs can be deleted\n");
diff --git a/lib/zclient.c b/lib/zclient.c
index d8f311fcec..92ff2537d5 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -888,7 +888,7 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp,
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
uint32_t api_flags)
{
- int ret = 0;
+ int i, ret = 0;
int nh_flags = api_nh->flags;
stream_putl(s, api_nh->vrf_id);
@@ -951,8 +951,17 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
sizeof(struct ethaddr));
/* Index of backup nexthop */
- if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
- stream_putc(s, api_nh->backup_idx);
+ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ /* Validate backup count */
+ if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) {
+ ret = -1;
+ goto done;
+ }
+
+ stream_putc(s, api_nh->backup_num);
+ for (i = 0; i < api_nh->backup_num; i++)
+ stream_putc(s, api_nh->backup_idx[i]);
+ }
done:
return ret;
@@ -1111,7 +1120,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
uint32_t api_flags)
{
- int ret = -1;
+ int i, ret = -1;
STREAM_GETL(s, api_nh->vrf_id);
STREAM_GETC(s, api_nh->type);
@@ -1163,8 +1172,15 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
sizeof(struct ethaddr));
/* Backup nexthop index */
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
- STREAM_GETC(s, api_nh->backup_idx);
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ STREAM_GETC(s, api_nh->backup_num);
+
+ if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS)
+ return -1;
+
+ for (i = 0; i < api_nh->backup_num; i++)
+ STREAM_GETC(s, api_nh->backup_idx[i]);
+ }
/* Success */
ret = 0;
@@ -1483,7 +1499,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
- n->backup_idx = znh->backup_idx;
+ n->backup_num = znh->backup_num;
+ memcpy(n->backup_idx, znh->backup_idx, n->backup_num);
}
return n;
@@ -1519,8 +1536,12 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
}
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (nh->backup_num > NEXTHOP_MAX_BACKUPS)
+ return -1;
+
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
- znh->backup_idx = nh->backup_idx;
+ znh->backup_num = nh->backup_num;
+ memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num);
}
return 0;
diff --git a/lib/zclient.h b/lib/zclient.h
index 3ded2f55d7..250824e612 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -394,8 +394,9 @@ struct zapi_nexthop {
uint32_t weight;
- /* Index of backup nexthop */
- uint8_t backup_idx;
+ /* Backup nexthops, for IP-FRR, TI-LFA, etc */
+ uint8_t backup_num;
+ uint8_t backup_idx[NEXTHOP_MAX_BACKUPS];
};
/*
diff --git a/lib/zlog.c b/lib/zlog.c
index 45726755f8..8dfd20371b 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -246,10 +246,10 @@ void zlog_tls_buffer_init(void)
fchown(mmfd, zlog_uid, zlog_gid);
#ifdef HAVE_POSIX_FALLOCATE
- if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) < 0) {
-#else
- if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) {
+ if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) != 0)
+ /* note next statement is under above if() */
#endif
+ if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) {
zlog_err("failed to allocate thread log buffer \"%s\": %s",
mmpath, strerror(errno));
goto out_anon_unlink;