summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/atomlist.h10
-rw-r--r--lib/command.c12
-rw-r--r--lib/command.h1
-rw-r--r--lib/command_graph.c2
-rw-r--r--lib/command_match.c6
-rw-r--r--lib/compiler.h7
-rw-r--r--lib/ferr.c12
-rw-r--r--lib/ferr.h1
-rw-r--r--lib/filter.c1375
-rw-r--r--lib/frr_pthread.c15
-rw-r--r--lib/frr_pthread.h3
-rw-r--r--lib/frrcu.c527
-rw-r--r--lib/frrcu.h172
-rw-r--r--lib/frrstr.c2
-rw-r--r--lib/if.c75
-rw-r--r--lib/if.h3
-rw-r--r--lib/libfrr.c5
-rw-r--r--lib/log.c21
-rw-r--r--lib/logicalrouter.c158
-rw-r--r--lib/logicalrouter.h49
-rw-r--r--lib/netns_other.c2
-rw-r--r--lib/ns.h12
-rw-r--r--lib/plist.c2
-rw-r--r--lib/pqueue.c185
-rw-r--r--lib/pqueue.h54
-rw-r--r--lib/prefix.c50
-rw-r--r--lib/prefix.h14
-rw-r--r--lib/ptm_lib.c2
-rw-r--r--lib/routemap.c203
-rw-r--r--lib/routemap.h38
-rw-r--r--lib/seqlock.c190
-rw-r--r--lib/seqlock.h40
-rw-r--r--lib/sigevent.c42
-rw-r--r--lib/stream.c14
-rw-r--r--lib/stream.h3
-rw-r--r--lib/subdir.am7
-rw-r--r--lib/thread.c106
-rw-r--r--lib/thread.h7
-rw-r--r--lib/typerb.c5
-rw-r--r--lib/typerb.h23
-rw-r--r--lib/typesafe.c13
-rw-r--r--lib/typesafe.h51
-rw-r--r--lib/vty.c9
-rw-r--r--lib/zebra.h5
44 files changed, 2474 insertions, 1059 deletions
diff --git a/lib/atomlist.h b/lib/atomlist.h
index e4098ccb54..621db6824f 100644
--- a/lib/atomlist.h
+++ b/lib/atomlist.h
@@ -135,8 +135,10 @@ macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \
macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \
_Atomic atomptr_t *hint) \
{ atomlist_del_hint(&h->ah, &item->field.ai, hint); } \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
-{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); } \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
+{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); \
+ /* TODO: Return NULL if not found */ \
+ return item; } \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ char *p = (char *)atomlist_pop(&h->ah); \
return p ? (type *)(p - offsetof(type, field)) : NULL; } \
@@ -273,9 +275,11 @@ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \
{ \
atomsort_del_hint(&h->ah, &item->field.ai, hint); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
atomsort_del_hint(&h->ah, &item->field.ai, NULL); \
+ /* TODO: Return NULL if not found */ \
+ return item; \
} \
macro_inline size_t prefix ## _count(struct prefix##_head *h) \
{ \
diff --git a/lib/command.c b/lib/command.c
index c8fbf22721..9dabc2af7e 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -89,7 +89,6 @@ const char *node_names[] = {
"aaa", // AAA_NODE,
"keychain", // KEYCHAIN_NODE,
"keychain key", // KEYCHAIN_KEY_NODE,
- "logical-router", // LOGICALROUTER_NODE,
"static ip", // IP_NODE,
"vrf", // VRF_NODE,
"interface", // INTERFACE_NODE,
@@ -290,7 +289,7 @@ vector cmd_make_strvec(const char *string)
const char *copy = string;
/* skip leading whitespace */
- while (isspace((int)*copy) && *copy != '\0')
+ while (isspace((unsigned char)*copy) && *copy != '\0')
copy++;
/* if the entire string was whitespace or a comment, return */
@@ -1456,7 +1455,6 @@ void cmd_exit(struct vty *vty)
break;
case INTERFACE_NODE:
case PW_NODE:
- case LOGICALROUTER_NODE:
case VRF_NODE:
case NH_GROUP_NODE:
case ZEBRA_NODE:
@@ -1936,7 +1934,7 @@ DEFUN(config_domainname,
{
struct cmd_token *word = argv[1];
- if (!isalpha((int)word->arg[0])) {
+ if (!isalpha((unsigned char)word->arg[0])) {
vty_out(vty, "Please specify string starting with alphabet\n");
return CMD_WARNING_CONFIG_FAILED;
}
@@ -1970,7 +1968,7 @@ DEFUN (config_hostname,
{
struct cmd_token *word = argv[1];
- if (!isalnum((int)word->arg[0])) {
+ if (!isalnum((unsigned char)word->arg[0])) {
vty_out(vty,
"Please specify string starting with alphabet or number\n");
return CMD_WARNING_CONFIG_FAILED;
@@ -2018,7 +2016,7 @@ DEFUN (config_password,
return CMD_SUCCESS;
}
- if (!isalnum((int)argv[idx_8]->arg[0])) {
+ if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
vty_out(vty,
"Please specify string starting with alphanumeric\n");
return CMD_WARNING_CONFIG_FAILED;
@@ -2098,7 +2096,7 @@ DEFUN (config_enable_password,
}
}
- if (!isalnum((int)argv[idx_8]->arg[0])) {
+ if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
vty_out(vty,
"Please specify string starting with alphanumeric\n");
return CMD_WARNING_CONFIG_FAILED;
diff --git a/lib/command.h b/lib/command.h
index 08d6128af4..8dc35a0fdc 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -98,7 +98,6 @@ enum node_type {
AAA_NODE, /* AAA node. */
KEYCHAIN_NODE, /* Key-chain node. */
KEYCHAIN_KEY_NODE, /* Key-chain key node. */
- LOGICALROUTER_NODE, /* Logical-Router node. */
IP_NODE, /* Static ip route node. */
VRF_NODE, /* VRF mode node. */
INTERFACE_NODE, /* Interface mode node. */
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 4757fd951f..d30d9ab702 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -97,7 +97,7 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname)
token->varname[i] = '_';
break;
default:
- token->varname[i] = tolower((int)varname[i]);
+ token->varname[i] = tolower((unsigned char)varname[i]);
}
token->varname[len] = '\0';
}
diff --git a/lib/command_match.c b/lib/command_match.c
index 9456e1585a..26d763849d 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -714,7 +714,7 @@ static enum match_type match_ipv4(const char *str)
dots++;
break;
}
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
@@ -765,7 +765,7 @@ static enum match_type match_ipv4_prefix(const char *str)
break;
}
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
@@ -797,7 +797,7 @@ static enum match_type match_ipv4_prefix(const char *str)
sp = str;
while (*str != '\0') {
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
diff --git a/lib/compiler.h b/lib/compiler.h
index 7c7f4ce294..6700ca9e8b 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -165,6 +165,13 @@ extern "C" {
_min_a < _min_b ? _min_a : _min_b; \
})
+#define numcmp(a, b) \
+ ({ \
+ typeof(a) _cmp_a = (a); \
+ typeof(b) _cmp_b = (b); \
+ (_cmp_a < _cmp_b) ? -1 : ((_cmp_a > _cmp_b) ? 1 : 0); \
+ })
+
#ifndef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
diff --git a/lib/ferr.c b/lib/ferr.c
index 65c0cf886d..8afc926c41 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -126,10 +126,8 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
if (code) {
ref = log_ref_get(code);
- if (!ref) {
- vty_out(vty, "Code %"PRIu32" - Unknown\n", code);
+ if (!ref)
return;
- }
listnode_add(errlist, ref);
}
@@ -197,8 +195,6 @@ void log_ref_init(void)
"Error Reference Texts");
}
pthread_mutex_unlock(&refs_mtx);
-
- install_element(VIEW_NODE, &show_error_code_cmd);
}
void log_ref_fini(void)
@@ -212,6 +208,12 @@ void log_ref_fini(void)
pthread_mutex_unlock(&refs_mtx);
}
+void log_ref_vty_init(void)
+{
+ install_element(VIEW_NODE, &show_error_code_cmd);
+}
+
+
const struct ferr *ferr_get_last(ferr_r errval)
{
struct ferr *last_error = pthread_getspecific(errkey);
diff --git a/lib/ferr.h b/lib/ferr.h
index 93d0ced538..a89b595e87 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -158,6 +158,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json);
*/
void log_ref_init(void);
void log_ref_fini(void);
+void log_ref_vty_init(void);
/* get error details.
*
diff --git a/lib/filter.c b/lib/filter.c
index 276df4b4d7..fe62ca1c13 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -60,6 +60,9 @@ struct filter {
/* Filter type information. */
enum filter_type type;
+ /* Sequence number */
+ int64_t seq;
+
/* Cisco access-list */
int cisco;
@@ -270,7 +273,7 @@ static struct access_list *access_list_insert(afi_t afi, const char *name)
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
@@ -406,23 +409,35 @@ void access_list_delete_hook(void (*func)(struct access_list *access))
access_master_mac.delete_hook = func;
}
-/* Add new filter to the end of specified access_list. */
-static void access_list_filter_add(struct access_list *access,
- struct filter *filter)
+/* Calculate new sequential number. */
+static int64_t filter_new_seq_get(struct access_list *access)
{
- filter->next = NULL;
- filter->prev = access->tail;
+ int64_t maxseq;
+ int64_t newseq;
+ struct filter *filter;
- if (access->tail)
- access->tail->next = filter;
- else
- access->head = filter;
- access->tail = filter;
+ maxseq = newseq = 0;
- /* Run hook function. */
- if (access->master->add_hook)
- (*access->master->add_hook)(access);
- route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
+ for (filter = access->head; filter; filter = filter->next) {
+ if (maxseq < filter->seq)
+ maxseq = filter->seq;
+ }
+
+ newseq = ((maxseq / 5) * 5) + 5;
+
+ return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return access list entry which has same seq number. */
+static struct filter *filter_seq_check(struct access_list *access,
+ int64_t seq)
+{
+ struct filter *filter;
+
+ for (filter = access->head; filter; filter = filter->next)
+ if (filter->seq == seq)
+ return filter;
+ return NULL;
}
/* If access_list has no filter then return 1. */
@@ -465,6 +480,58 @@ static void access_list_filter_delete(struct access_list *access,
access_list_delete(access);
}
+/* Add new filter to the end of specified access_list. */
+static void access_list_filter_add(struct access_list *access,
+ struct filter *filter)
+{
+ struct filter *replace;
+ struct filter *point;
+
+ /* Automatic asignment of seq no. */
+ if (filter->seq == -1)
+ filter->seq = filter_new_seq_get(access);
+
+ if (access->tail && filter->seq > access->tail->seq)
+ point = NULL;
+ else {
+ /* Is there any same seq access list filter? */
+ replace = filter_seq_check(access, filter->seq);
+ if (replace)
+ access_list_filter_delete(access, replace);
+
+ /* Check insert point. */
+ for (point = access->head; point; point = point->next)
+ if (point->seq >= filter->seq)
+ break;
+ }
+
+ /* In case of this is the first element of the list. */
+ filter->next = point;
+
+ if (point) {
+ if (point->prev)
+ point->prev->next = filter;
+ else
+ access->head = filter;
+
+ filter->prev = point->prev;
+ point->prev = filter;
+ } else {
+ if (access->tail)
+ access->tail->next = filter;
+ else
+ access->head = filter;
+
+ filter->prev = access->tail;
+ access->tail = filter;
+ }
+
+ /* Run hook function. */
+ if (access->master->add_hook)
+ (*access->master->add_hook)(access);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
+}
+
/*
deny Specify packets to reject
permit Specify packets to forward
@@ -553,12 +620,13 @@ static int vty_access_list_remark_unset(struct vty *vty, afi_t afi,
}
static int filter_set_cisco(struct vty *vty, const char *name_str,
- const char *type_str, const char *addr_str,
- const char *addr_mask_str, const char *mask_str,
- const char *mask_mask_str, int extended, int set)
+ const char *seq, const char *type_str,
+ const char *addr_str, const char *addr_mask_str,
+ const char *mask_str, const char *mask_mask_str,
+ int extended, int set)
{
int ret;
- enum filter_type type;
+ enum filter_type type = FILTER_DENY;
struct filter *mfilter;
struct filter_cisco *filter;
struct access_list *access;
@@ -566,15 +634,21 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
struct in_addr addr_mask;
struct in_addr mask;
struct in_addr mask_mask;
+ int64_t seqnum = -1;
+
+ if (seq)
+ seqnum = (int64_t)atol(seq);
/* Check of filter type. */
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "%% filter type must be permit or deny\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (type_str) {
+ if (strncmp(type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp(type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else {
+ vty_out(vty, "%% filter type must be permit or deny\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
ret = inet_aton(addr_str, &addr);
@@ -606,6 +680,7 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
mfilter = filter_new();
mfilter->type = type;
mfilter->cisco = 1;
+ mfilter->seq = seqnum;
filter = &mfilter->u.cfilter;
filter->extended = extended;
filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
@@ -640,163 +715,311 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
/* Standard access-list */
DEFUN (access_list_standard,
access_list_standard_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n"
"Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 3;
- int idx_ipv4_2 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+ char *wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ address = argv[idx]->arg;
+ wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, wildcard, NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_nomask,
access_list_standard_nomask_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 3;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_host,
access_list_standard_host_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A single host address\n"
"Address to match\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_any,
access_list_standard_any_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> any",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any source host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 1);
}
DEFUN (no_access_list_standard,
no_access_list_standard_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n"
"Wildcard bits\n")
{
- int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, NULL, NULL, 0, 0);
+ int idx_acl = 1;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+ char *wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ address = argv[idx]->arg;
+ wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, wildcard, NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_nomask,
no_access_list_standard_nomask_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_host,
no_access_list_standard_host_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A single host address\n"
"Address to match\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_any,
no_access_list_standard_any_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> any",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any source host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 0);
}
/* Extended access-list */
DEFUN (access_list_extended,
access_list_extended_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -806,23 +1029,45 @@ DEFUN (access_list_extended,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- int idx_ipv4_3 = 6;
- int idx_ipv4_4 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- argv[idx_ipv4_4]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 2]->arg;
+ dst_wildcard = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, dst_wildcard, 1, 1);
}
DEFUN (access_list_extended_mask_any,
access_list_extended_mask_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -831,21 +1076,42 @@ DEFUN (access_list_extended_mask_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, "0.0.0.0",
- "255.255.255.255", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, "0.0.0.0", "255.255.255.255", 1,
+ 1);
}
DEFUN (access_list_extended_any_mask,
access_list_extended_any_mask_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -854,21 +1120,42 @@ DEFUN (access_list_extended_any_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ dst = argv[idx]->arg;
+ dst_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
+ 1, 1);
}
DEFUN (access_list_extended_any_any,
access_list_extended_any_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -876,18 +1163,33 @@ DEFUN (access_list_extended_any_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 1);
}
DEFUN (access_list_extended_mask_host,
access_list_extended_mask_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -897,22 +1199,43 @@ DEFUN (access_list_extended_mask_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- int idx_ipv4_3 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- "0.0.0.0", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, "0.0.0.0", 1, 1);
}
DEFUN (access_list_extended_host_mask,
access_list_extended_host_mask_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -922,22 +1245,43 @@ DEFUN (access_list_extended_host_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg,
- argv[idx_ipv4_3]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 1]->arg;
+ dst_wildcard = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, dst_wildcard, 1, 1);
}
DEFUN (access_list_extended_host_host,
access_list_extended_host_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -947,21 +1291,41 @@ DEFUN (access_list_extended_host_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1,
- 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, "0.0.0.0", 1, 1);
}
DEFUN (access_list_extended_any_host,
access_list_extended_any_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -970,19 +1334,39 @@ DEFUN (access_list_extended_any_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 6;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ dst = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
+ 1);
}
DEFUN (access_list_extended_host_any,
access_list_extended_host_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -991,20 +1375,39 @@ DEFUN (access_list_extended_host_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ src = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
"0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 1);
}
DEFUN (no_access_list_extended,
no_access_list_extended_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1014,24 +1417,46 @@ DEFUN (no_access_list_extended,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 7;
- int idx_ipv4_4 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- argv[idx_ipv4_4]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 2]->arg;
+ dst_wildcard = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, dst_wildcard, 1, 0);
}
DEFUN (no_access_list_extended_mask_any,
no_access_list_extended_mask_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1040,22 +1465,43 @@ DEFUN (no_access_list_extended_mask_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, "0.0.0.0",
- "255.255.255.255", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, "0.0.0.0", "255.255.255.255", 1,
+ 0);
}
DEFUN (no_access_list_extended_any_mask,
no_access_list_extended_any_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1064,22 +1510,43 @@ DEFUN (no_access_list_extended_any_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ dst = argv[idx]->arg;
+ dst_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
+ 1, 0);
}
DEFUN (no_access_list_extended_any_any,
no_access_list_extended_any_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1087,19 +1554,34 @@ DEFUN (no_access_list_extended_any_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 0);
}
DEFUN (no_access_list_extended_mask_host,
no_access_list_extended_mask_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1109,23 +1591,44 @@ DEFUN (no_access_list_extended_mask_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- "0.0.0.0", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, "0.0.0.0", 1, 0);
}
DEFUN (no_access_list_extended_host_mask,
no_access_list_extended_host_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1135,23 +1638,44 @@ DEFUN (no_access_list_extended_host_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 7;
- int idx_ipv4_3 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg,
- argv[idx_ipv4_3]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 1]->arg;
+ dst_wildcard = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, dst_wildcard, 1, 0);
}
DEFUN (no_access_list_extended_host_host,
no_access_list_extended_host_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1161,22 +1685,42 @@ DEFUN (no_access_list_extended_host_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1,
- 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, "0.0.0.0", 1, 0);
}
DEFUN (no_access_list_extended_any_host,
no_access_list_extended_any_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1185,20 +1729,40 @@ DEFUN (no_access_list_extended_any_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 7;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ dst = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
+ 0);
}
DEFUN (no_access_list_extended_host_any,
no_access_list_extended_host_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1207,23 +1771,41 @@ DEFUN (no_access_list_extended_host_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ src = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
"0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 0);
}
static int filter_set_zebra(struct vty *vty, const char *name_str,
- const char *type_str, afi_t afi,
+ const char *seq, const char *type_str, afi_t afi,
const char *prefix_str, int exact, int set)
{
int ret;
- enum filter_type type;
+ enum filter_type type = FILTER_DENY;
struct filter *mfilter;
struct filter_zebra *filter;
struct access_list *access;
struct prefix p;
+ int64_t seqnum = -1;
if (strlen(name_str) > ACL_NAMSIZ) {
vty_out(vty,
@@ -1233,14 +1815,19 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (seq)
+ seqnum = (int64_t)atol(seq);
+
/* Check of filter type. */
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "filter type must be [permit|deny]\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (type_str) {
+ if (strncmp(type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp(type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else {
+ vty_out(vty, "filter type must be [permit|deny]\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
/* Check string format of prefix and prefixlen. */
@@ -1269,6 +1856,7 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
mfilter = filter_new();
mfilter->type = type;
+ mfilter->seq = seqnum;
filter = &mfilter->u.zfilter;
prefix_copy(&filter->prefix, &p);
@@ -1298,67 +1886,145 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
DEFUN (mac_access_list,
mac_access_list_cmd,
- "mac access-list WORD <deny|permit> X:X:X:X:X:X",
+ "mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
- argv[4]->arg, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *mac = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X:X:X:X:X", &idx);
+ if (idx)
+ mac = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
+ mac, 0, 1);
}
DEFUN (no_mac_access_list,
no_mac_access_list_cmd,
- "no mac access-list WORD <deny|permit> X:X:X:X:X:X",
+ "no mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
- argv[5]->arg, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *mac = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X:X:X:X:X", &idx);
+ if (idx)
+ mac = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
+ mac, 0, 0);
}
DEFUN (mac_access_list_any,
mac_access_list_any_cmd,
- "mac access-list WORD <deny|permit> any",
+ "mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
"00:00:00:00:00:00", 0, 1);
}
DEFUN (no_mac_access_list_any,
no_mac_access_list_any_cmd,
- "no mac access-list WORD <deny|permit> any",
+ "no mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
"00:00:00:00:00:00", 0, 0);
}
DEFUN (access_list_exact,
access_list_exact_cmd,
- "access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
+ "access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n"
@@ -1366,41 +2032,71 @@ DEFUN (access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 1;
- int idx_permit_deny = 2;
- int idx_ipv4_prefixlen = 3;
- idx = idx_ipv4_prefixlen;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP,
- argv[idx_ipv4_prefixlen]->arg, exact, 1);
+ return filter_set_zebra(vty, argv[1]->arg, seq, permit_deny,
+ AFI_IP, prefix, exact, 1);
}
DEFUN (access_list_any,
access_list_any_cmd,
- "access-list WORD <deny|permit> any",
+ "access-list WORD [seq (1-4294967295)] <deny|permit> any",
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n")
{
int idx_word = 1;
- int idx_permit_deny = 2;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0",
- 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP, "0.0.0.0/0", 0, 1);
}
DEFUN (no_access_list_exact,
no_access_list_exact_cmd,
- "no access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
+ "no access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
NO_STR
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n"
@@ -1408,34 +2104,62 @@ DEFUN (no_access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 2;
- int idx_permit_deny = 3;
- int idx_ipv4_prefixlen = 4;
- idx = idx_ipv4_prefixlen;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP,
- argv[idx_ipv4_prefixlen]->arg, exact, 0);
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny,
+ AFI_IP, prefix, exact, 0);
}
DEFUN (no_access_list_any,
no_access_list_any_cmd,
- "no access-list WORD <deny|permit> any",
+ "no access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n")
{
- int idx_word = 2;
- int idx_permit_deny = 3;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0",
- 0, 0);
+ int idx_word = 1;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP, "0.0.0.0/0", 0, 0);
}
DEFUN (no_access_list_all,
@@ -1536,10 +2260,12 @@ DEFUN (no_access_list_remark_comment,
DEFUN (ipv6_access_list_exact,
ipv6_access_list_exact_cmd,
- "ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]",
+ "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"IPv6 prefix\n"
@@ -1548,41 +2274,73 @@ DEFUN (ipv6_access_list_exact,
int idx = 0;
int exact = 0;
int idx_word = 2;
- int idx_allow = 3;
- int idx_addr = 4;
- idx = idx_addr;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X::X:X/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg, argv[idx_allow]->text,
- AFI_IP6, argv[idx_addr]->arg, exact, 1);
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, prefix, exact, 1);
}
DEFUN (ipv6_access_list_any,
ipv6_access_list_any_cmd,
- "ipv6 access-list WORD <deny|permit> any",
+ "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefixi to match\n")
{
int idx_word = 2;
- int idx_permit_deny = 3;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0,
- 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, "::/0", 0, 1);
}
DEFUN (no_ipv6_access_list_exact,
no_ipv6_access_list_exact_cmd,
- "no ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]",
+ "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
NO_STR
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 3ffe:506::/32\n"
@@ -1590,35 +2348,64 @@ DEFUN (no_ipv6_access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 3;
- int idx_permit_deny = 4;
- int idx_ipv6_prefixlen = 5;
- idx = idx_ipv6_prefixlen;
-
+ int idx_word = 2;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X::X:X/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6,
- argv[idx_ipv6_prefixlen]->arg, exact, 0);
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, prefix, exact, 0);
}
DEFUN (no_ipv6_access_list_any,
no_ipv6_access_list_any_cmd,
- "no ipv6 access-list WORD <deny|permit> any",
+ "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefixi to match\n")
{
- int idx_word = 3;
- int idx_permit_deny = 4;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0,
- 0);
+ int idx_word = 2;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, "::/0", 0, 0);
}
@@ -1748,7 +2535,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
write = 0;
}
- vty_out(vty, " %s%s", filter_type_str(mfilter),
+ vty_out(vty, " seq %" PRId64, mfilter->seq);
+ vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " " : "");
if (!mfilter->cisco)
@@ -1795,7 +2583,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
write = 0;
}
- vty_out(vty, " %s%s", filter_type_str(mfilter),
+ vty_out(vty, " seq %" PRId64, mfilter->seq);
+ vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " " : "");
if (!mfilter->cisco)
@@ -1978,11 +2767,12 @@ static int config_write_access(struct vty *vty, afi_t afi)
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s %s",
+ vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
(afi == AFI_IP) ? ("")
: ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
- access->name, filter_type_str(mfilter));
+ access->name, mfilter->seq,
+ filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
@@ -2004,11 +2794,12 @@ static int config_write_access(struct vty *vty, afi_t afi)
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s %s",
+ vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
(afi == AFI_IP) ? ("")
: ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
- access->name, filter_type_str(mfilter));
+ access->name, mfilter->seq,
+ filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index e588571c01..bdb6c2a397 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -133,18 +133,29 @@ int frr_pthread_set_name(struct frr_pthread *fpt)
return ret;
}
+static void *frr_pthread_inner(void *arg)
+{
+ struct frr_pthread *fpt = arg;
+
+ rcu_thread_start(fpt->rcu_thread);
+ return fpt->attr.start(fpt);
+}
+
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
{
int ret;
- ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
+ fpt->rcu_thread = rcu_thread_prepare();
+ ret = pthread_create(&fpt->thread, attr, frr_pthread_inner, fpt);
/*
* Per pthread_create(3), the contents of fpt->thread are undefined if
* pthread_create() did not succeed. Reset this value to zero.
*/
- if (ret < 0)
+ if (ret < 0) {
+ rcu_thread_unprepare(fpt->rcu_thread);
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+ }
return ret;
}
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index 3afe7ba966..6096a50370 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -23,6 +23,7 @@
#include <pthread.h>
#include "frratomic.h"
#include "memory.h"
+#include "frrcu.h"
#include "thread.h"
#ifdef __cplusplus
@@ -50,6 +51,8 @@ struct frr_pthread {
/* pthread id */
pthread_t thread;
+ struct rcu_thread *rcu_thread;
+
/* thread master for this pthread's thread.c event loop */
struct thread_master *master;
diff --git a/lib/frrcu.c b/lib/frrcu.c
new file mode 100644
index 0000000000..7e6475b648
--- /dev/null
+++ b/lib/frrcu.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* implementation notes: this is an epoch-based RCU implementation. rcu_seq
+ * (global variable) counts the current epoch. Threads hold a specific epoch
+ * in rcu_read_lock(). This is the oldest epoch a thread might be accessing
+ * data from.
+ *
+ * The rcu_seq global is only pushed forward on rcu_read_lock() and
+ * rcu_read_unlock() calls. This makes things a tad more efficient since
+ * those are the only places it matters:
+ * - on rcu_read_lock, we don't want to hold an old epoch pointlessly
+ * - on rcu_read_unlock, we want to make sure we're not stuck on an old epoch
+ * when heading into a long idle period where no thread holds RCU
+ *
+ * rcu_thread structures themselves are RCU-free'd.
+ *
+ * rcu_head structures are the most iffy; normally for an ATOMLIST we would
+ * need to make sure we use rcu_free or pthread_rwlock to deallocate old items
+ * to prevent ABA or use-after-free problems. However, our ATOMLIST code
+ * guarantees that if the list remains non-empty in all cases, we only need
+ * the "last" pointer to do an "add_tail()", i.e. we can't run into ABA/UAF
+ * issues - but we do need to keep at least 1 item on the list.
+ *
+ * (Search the atomlist code for all uses of "last")
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "frrcu.h"
+#include "seqlock.h"
+#include "atomlist.h"
+
+DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread")
+DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier")
+
+DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
+
+PREDECL_ATOMLIST(rcu_threads)
+struct rcu_thread {
+ struct rcu_threads_item head;
+
+ struct rcu_head rcu_head;
+
+ struct seqlock rcu;
+
+ /* only accessed by thread itself, not atomic */
+ unsigned depth;
+};
+DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head)
+
+static const struct rcu_action rcua_next = { .type = RCUA_NEXT };
+static const struct rcu_action rcua_end = { .type = RCUA_END };
+static const struct rcu_action rcua_close = { .type = RCUA_CLOSE };
+
+struct rcu_next {
+ struct rcu_head head_free;
+ struct rcu_head head_next;
+};
+
+#define rcu_free_internal(mtype, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_FREE, \
+ .u.free = { \
+ .mt = mtype, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ _rcu_head->action = &_rcu_action; \
+ rcu_heads_add_tail(&rcu_heads, _rcu_head); \
+ } while (0)
+
+/* primary global RCU position */
+static struct seqlock rcu_seq;
+/* this is set to rcu_seq whenever something is added on the RCU queue.
+ * rcu_read_lock() and rcu_read_unlock() will then bump rcu_seq up one step.
+ */
+static _Atomic seqlock_val_t rcu_dirty;
+
+static struct rcu_threads_head rcu_threads;
+static struct rcu_heads_head rcu_heads;
+
+/* main thread & RCU sweeper have pre-setup rcu_thread structures. The
+ * reasons are different:
+ *
+ * - rcu_thread_main is there because the main thread isn't started like
+ * other threads, it's implicitly created when the program is started. So
+ * rcu_thread_main matches up implicitly.
+ *
+ * - rcu_thread_rcu isn't actually put on the rcu_threads list (makes no
+ * sense really), it only exists so we can call RCU-using functions from
+ * the RCU thread without special handling in rcu_read_lock/unlock.
+ */
+static struct rcu_thread rcu_thread_main;
+static struct rcu_thread rcu_thread_rcu;
+
+static pthread_t rcu_pthread;
+static pthread_key_t rcu_thread_key;
+static bool rcu_active;
+
+static void rcu_start(void);
+static void rcu_bump(void);
+
+/*
+ * preinitialization for main thread
+ */
+static void rcu_thread_end(void *rcu_thread);
+
+static void rcu_preinit(void) __attribute__((constructor));
+static void rcu_preinit(void)
+{
+ struct rcu_thread *rt;
+
+ rt = &rcu_thread_main;
+ rt->depth = 1;
+ seqlock_init(&rt->rcu);
+ seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL);
+
+ pthread_key_create(&rcu_thread_key, rcu_thread_end);
+ pthread_setspecific(rcu_thread_key, rt);
+
+ rcu_threads_add_tail(&rcu_threads, rt);
+
+ /* RCU sweeper's rcu_thread is a dummy, NOT added to rcu_threads */
+ rt = &rcu_thread_rcu;
+ rt->depth = 1;
+
+ seqlock_init(&rcu_seq);
+ seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL);
+}
+
+static struct rcu_thread *rcu_self(void)
+{
+ return (struct rcu_thread *)pthread_getspecific(rcu_thread_key);
+}
+
+/*
+ * thread management (for the non-main thread)
+ */
+struct rcu_thread *rcu_thread_prepare(void)
+{
+ struct rcu_thread *rt, *cur;
+
+ rcu_assert_read_locked();
+
+ if (!rcu_active)
+ rcu_start();
+
+ cur = rcu_self();
+ assert(cur->depth);
+
+ /* new thread always starts with rcu_read_lock held at depth 1, and
+ * holding the same epoch as the parent (this makes it possible to
+ * use RCU for things passed into the thread through its arg)
+ */
+ rt = XCALLOC(MTYPE_RCU_THREAD, sizeof(*rt));
+ rt->depth = 1;
+
+ seqlock_init(&rt->rcu);
+ seqlock_acquire(&rt->rcu, &cur->rcu);
+
+ rcu_threads_add_tail(&rcu_threads, rt);
+
+ return rt;
+}
+
+void rcu_thread_start(struct rcu_thread *rt)
+{
+ pthread_setspecific(rcu_thread_key, rt);
+}
+
+void rcu_thread_unprepare(struct rcu_thread *rt)
+{
+ if (rt == &rcu_thread_rcu)
+ return;
+
+ rt->depth = 1;
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+
+ rcu_bump();
+ if (rt != &rcu_thread_main)
+ /* this free() happens after seqlock_release() below */
+ rcu_free_internal(MTYPE_RCU_THREAD, rt, rcu_head);
+
+ rcu_threads_del(&rcu_threads, rt);
+ seqlock_release(&rt->rcu);
+}
+
+static void rcu_thread_end(void *rtvoid)
+{
+ struct rcu_thread *rt = rtvoid;
+ rcu_thread_unprepare(rt);
+}
+
+/*
+ * main RCU control aspects
+ */
+
+static void rcu_bump(void)
+{
+ struct rcu_next *rn;
+
+ rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn));
+
+ /* note: each RCUA_NEXT item corresponds to exactly one seqno bump.
+ * This means we don't need to communicate which seqno is which
+ * RCUA_NEXT, since we really don't care.
+ */
+
+ /*
+ * Important race condition: while rcu_heads_add_tail is executing,
+ * there is an intermediate point where the rcu_heads "last" pointer
+ * already points to rn->head_next, but rn->head_next isn't added to
+ * the list yet. That means any other "add_tail" calls append to this
+ * item, which isn't fully on the list yet. Freeze this thread at
+ * that point and look at another thread doing a rcu_bump. It adds
+ * these two items and then does a seqlock_bump. But the rcu_heads
+ * list is still "interrupted" and there's no RCUA_NEXT on the list
+ * yet (from either the frozen thread or the second thread). So
+ * rcu_main() might actually hit the end of the list at the
+ * "interrupt".
+ *
+ * This situation is prevented by requiring that rcu_read_lock is held
+ * for any calls to rcu_bump, since if we're holding the current RCU
+ * epoch, that means rcu_main can't be chewing on rcu_heads and hit
+ * that interruption point. Only by the time the thread has continued
+ * to rcu_read_unlock() - and therefore completed the add_tail - the
+ * RCU sweeper gobbles up the epoch and can be sure to find at least
+ * the RCUA_NEXT and RCUA_FREE items on rcu_heads.
+ */
+ rn->head_next.action = &rcua_next;
+ rcu_heads_add_tail(&rcu_heads, &rn->head_next);
+
+ /* free rn that we allocated above.
+ *
+ * This is INTENTIONALLY not built into the RCUA_NEXT action. This
+ * ensures that after the action above is popped off the queue, there
+ * is still at least 1 item on the RCU queue. This means we never
+ * delete the last item, which is extremely important since it keeps
+ * the atomlist ->last pointer alive and well.
+ *
+ * If we were to "run dry" on the RCU queue, add_tail may run into the
+ * "last item is being deleted - start over" case, and then we may end
+ * up accessing old RCU queue items that are already free'd.
+ */
+ rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free);
+
+ /* Only allow the RCU sweeper to run after these 2 items are queued.
+ *
+ * If another thread enqueues some RCU action in the intermediate
+ * window here, nothing bad happens - the queued action is associated
+ * with a larger seq# than strictly necessary. Thus, it might get
+ * executed a bit later, but that's not a problem.
+ *
+ * If another thread acquires the read lock in this window, it holds
+ * the previous epoch, but its RCU queue actions will be in the next
+ * epoch. This isn't a problem either, just a tad inefficient.
+ */
+ seqlock_bump(&rcu_seq);
+}
+
+static void rcu_bump_maybe(void)
+{
+ seqlock_val_t dirty;
+
+ dirty = atomic_load_explicit(&rcu_dirty, memory_order_relaxed);
+ /* no problem if we race here and multiple threads bump rcu_seq;
+ * bumping too much causes no issues while not bumping enough will
+ * result in delayed cleanup
+ */
+ if (dirty == seqlock_cur(&rcu_seq))
+ rcu_bump();
+}
+
+void rcu_read_lock(void)
+{
+ struct rcu_thread *rt = rcu_self();
+
+ assert(rt);
+ if (rt->depth++ > 0)
+ return;
+
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+ /* need to hold RCU for bump ... */
+ rcu_bump_maybe();
+ /* ... but no point in holding the old epoch if we just bumped */
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+}
+
+void rcu_read_unlock(void)
+{
+ struct rcu_thread *rt = rcu_self();
+
+ assert(rt && rt->depth);
+ if (--rt->depth > 0)
+ return;
+ rcu_bump_maybe();
+ seqlock_release(&rt->rcu);
+}
+
+void rcu_assert_read_locked(void)
+{
+ struct rcu_thread *rt = rcu_self();
+ assert(rt && rt->depth && seqlock_held(&rt->rcu));
+}
+
+void rcu_assert_read_unlocked(void)
+{
+ struct rcu_thread *rt = rcu_self();
+ assert(rt && !rt->depth && !seqlock_held(&rt->rcu));
+}
+
+/*
+ * RCU resource-release thread
+ */
+
+static void *rcu_main(void *arg);
+
+static void rcu_start(void)
+{
+ /* ensure we never handle signals on the RCU thread by blocking
+ * everything here (new thread inherits signal mask)
+ */
+ sigset_t oldsigs, blocksigs;
+
+ sigfillset(&blocksigs);
+ pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs);
+
+ rcu_active = true;
+
+ assert(!pthread_create(&rcu_pthread, NULL, rcu_main, NULL));
+
+ pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
+
+#ifdef HAVE_PTHREAD_SETNAME_NP
+# ifdef GNU_LINUX
+ pthread_setname_np(rcu_pthread, "RCU sweeper");
+# elif defined(__NetBSD__)
+ pthread_setname_np(rcu_pthread, "RCU sweeper", NULL);
+# endif
+#elif defined(HAVE_PTHREAD_SET_NAME_NP)
+ pthread_set_name_np(rcu_pthread, "RCU sweeper");
+#endif
+}
+
+static void rcu_do(struct rcu_head *rh)
+{
+ struct rcu_head_close *rhc;
+ void *p;
+
+ switch (rh->action->type) {
+ case RCUA_FREE:
+ p = (char *)rh - rh->action->u.free.offset;
+ if (rh->action->u.free.mt)
+ qfree(rh->action->u.free.mt, p);
+ else
+ free(p);
+ break;
+ case RCUA_CLOSE:
+ rhc = container_of(rh, struct rcu_head_close,
+ rcu_head);
+ close(rhc->fd);
+ break;
+ case RCUA_CALL:
+ p = (char *)rh - rh->action->u.call.offset;
+ rh->action->u.call.fptr(p);
+ break;
+
+ case RCUA_INVALID:
+ case RCUA_NEXT:
+ case RCUA_END:
+ default:
+ assert(0);
+ }
+}
+
+static void rcu_watchdog(struct rcu_thread *rt)
+{
+#if 0
+ /* future work: print a backtrace for the thread that's holding up
+ * RCU. The only (good) way of doing that is to send a signal to the
+ * other thread, save away the backtrace in the signal handler, and
+ * block here until the signal is done processing.
+ *
+ * Just haven't implemented that yet.
+ */
+ fprintf(stderr, "RCU watchdog %p\n", rt);
+#endif
+}
+
+static void *rcu_main(void *arg)
+{
+ struct rcu_thread *rt;
+ struct rcu_head *rh = NULL;
+ bool end = false;
+ struct timespec maxwait;
+
+ seqlock_val_t rcuval = SEQLOCK_STARTVAL;
+
+ pthread_setspecific(rcu_thread_key, &rcu_thread_rcu);
+
+ while (!end) {
+ seqlock_wait(&rcu_seq, rcuval);
+
+ /* RCU watchdog timeout, TODO: configurable value */
+ clock_gettime(CLOCK_MONOTONIC, &maxwait);
+ maxwait.tv_nsec += 100 * 1000 * 1000;
+ if (maxwait.tv_nsec >= 1000000000) {
+ maxwait.tv_sec++;
+ maxwait.tv_nsec -= 1000000000;
+ }
+
+ frr_each (rcu_threads, &rcu_threads, rt)
+ if (!seqlock_timedwait(&rt->rcu, rcuval, &maxwait)) {
+ rcu_watchdog(rt);
+ seqlock_wait(&rt->rcu, rcuval);
+ }
+
+ while ((rh = rcu_heads_pop(&rcu_heads))) {
+ if (rh->action->type == RCUA_NEXT)
+ break;
+ else if (rh->action->type == RCUA_END)
+ end = true;
+ else
+ rcu_do(rh);
+ }
+
+ rcuval += SEQLOCK_INCR;
+ }
+
+ /* rcu_shutdown can only be called singlethreaded, and it does a
+ * pthread_join, so it should be impossible that anything ended up
+ * on the queue after RCUA_END
+ */
+#if 1
+ assert(!rcu_heads_first(&rcu_heads));
+#else
+ while ((rh = rcu_heads_pop(&rcu_heads)))
+ if (rh->action->type >= RCUA_FREE)
+ rcu_do(rh);
+#endif
+ return NULL;
+}
+
+void rcu_shutdown(void)
+{
+ static struct rcu_head rcu_head_end;
+ struct rcu_thread *rt = rcu_self();
+ void *retval;
+
+ if (!rcu_active)
+ return;
+
+ rcu_assert_read_locked();
+ assert(rcu_threads_count(&rcu_threads) == 1);
+
+ rcu_enqueue(&rcu_head_end, &rcua_end);
+
+ rt->depth = 0;
+ seqlock_release(&rt->rcu);
+ seqlock_release(&rcu_seq);
+ rcu_active = false;
+
+ /* clearing rcu_active is before pthread_join in case we hang in
+ * pthread_join & get a SIGTERM or something - in that case, just
+ * ignore the maybe-still-running RCU thread
+ */
+ if (pthread_join(rcu_pthread, &retval) == 0) {
+ seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL);
+ seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL);
+ rt->depth = 1;
+ }
+}
+
+/*
+ * RCU'd free functions
+ */
+
+void rcu_enqueue(struct rcu_head *rh, const struct rcu_action *action)
+{
+ /* refer to rcu_bump() for why we need to hold RCU when adding items
+ * to rcu_heads
+ */
+ rcu_assert_read_locked();
+
+ rh->action = action;
+
+ if (!rcu_active) {
+ rcu_do(rh);
+ return;
+ }
+ rcu_heads_add_tail(&rcu_heads, rh);
+ atomic_store_explicit(&rcu_dirty, seqlock_cur(&rcu_seq),
+ memory_order_relaxed);
+}
+
+void rcu_close(struct rcu_head_close *rhc, int fd)
+{
+ rhc->fd = fd;
+ rcu_enqueue(&rhc->rcu_head, &rcua_close);
+}
diff --git a/lib/frrcu.h b/lib/frrcu.h
new file mode 100644
index 0000000000..8f789303cc
--- /dev/null
+++ b/lib/frrcu.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRRCU_H
+#define _FRRCU_H
+
+#include "memory.h"
+#include "atomlist.h"
+#include "seqlock.h"
+
+/* quick RCU primer:
+ * There's a global sequence counter. Whenever a thread does a
+ * rcu_read_lock(), it is marked as holding the current sequence counter.
+ * When something is cleaned with RCU, the global sequence counter is
+ * increased and the item is queued for cleanup - *after* all threads are
+ * at a more recent sequence counter (or no sequence counter / unheld).
+ *
+ * So, by delaying resource cleanup, RCU ensures that things don't go away
+ * while another thread may hold a (stale) reference.
+ *
+ * Note that even if a thread is in rcu_read_lock(), it is invalid for that
+ * thread to access bits after rcu_free() & co on them. This is a design
+ * choice to allow no-op'ing out the entire RCU mechanism if we're running
+ * singlethreaded. (Also allows some optimization on the counter bumping.)
+ *
+ * differences from Linux Kernel RCU:
+ * - there's no rcu_synchronize(), if you really need to defer something
+ * use rcu_call() (and double check it's really necessary)
+ * - rcu_dereference() and rcu_assign_pointer() don't exist, use atomic_*
+ * instead (ATOM* list structures do the right thing)
+ */
+
+/* opaque */
+struct rcu_thread;
+
+/* called before new thread creation, sets up rcu thread info for new thread
+ * before it actually exits. This ensures possible RCU references are held
+ * for thread startup.
+ *
+ * return value must be passed into the new thread's call to rcu_thread_start()
+ */
+extern struct rcu_thread *rcu_thread_prepare(void);
+
+/* cleanup in case pthread_create() fails */
+extern void rcu_thread_unprepare(struct rcu_thread *rcu_thread);
+
+/* called early in the new thread, with the return value from the above.
+ * NB: new thread is initially in RCU-held state! (at depth 1)
+ *
+ * TBD: maybe inherit RCU state from rcu_thread_prepare()?
+ */
+extern void rcu_thread_start(struct rcu_thread *rcu_thread);
+
+/* thread exit is handled through pthread_key_create's destructor function */
+
+/* global RCU shutdown - must be called with only 1 active thread left. waits
+ * until remaining RCU actions are done & RCU thread has exited.
+ *
+ * This is mostly here to get a clean exit without memleaks.
+ */
+extern void rcu_shutdown(void);
+
+/* enter / exit RCU-held state. counter-based, so can be called nested. */
+extern void rcu_read_lock(void);
+extern void rcu_read_unlock(void);
+
+/* for debugging / safety checks */
+extern void rcu_assert_read_locked(void);
+extern void rcu_assert_read_unlocked(void);
+
+enum rcu_action_type {
+ RCUA_INVALID = 0,
+ /* used internally by the RCU code, shouldn't ever show up outside */
+ RCUA_NEXT,
+ RCUA_END,
+ /* normal RCU actions, for outside use */
+ RCUA_FREE,
+ RCUA_CLOSE,
+ RCUA_CALL,
+};
+
+/* since rcu_head is intended to be embedded into structs which may exist
+ * with lots of copies, rcu_head is shrunk down to its absolute minimum -
+ * the atomlist pointer + a pointer to this action struct.
+ */
+struct rcu_action {
+ enum rcu_action_type type;
+
+ union {
+ struct {
+ struct memtype *mt;
+ ptrdiff_t offset;
+ } free;
+
+ struct {
+ void (*fptr)(void *arg);
+ ptrdiff_t offset;
+ } call;
+ } u;
+};
+
+/* RCU cleanup function queue item */
+PREDECL_ATOMLIST(rcu_heads)
+struct rcu_head {
+ struct rcu_heads_item head;
+ const struct rcu_action *action;
+};
+
+/* special RCU head for delayed fd-close */
+struct rcu_head_close {
+ struct rcu_head rcu_head;
+ int fd;
+};
+
+/* enqueue RCU action - use the macros below to get the rcu_action set up */
+extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action);
+
+/* RCU free() and file close() operations.
+ *
+ * freed memory / closed fds become _immediately_ unavailable to the calling
+ * thread, but will remain available for other threads until they have passed
+ * into RCU-released state.
+ */
+
+/* may be called with NULL mt to do non-MTYPE free() */
+#define rcu_free(mtype, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_FREE, \
+ .u.free = { \
+ .mt = mtype, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ rcu_enqueue(_rcu_head, &_rcu_action); \
+ } while (0)
+
+/* use this sparingly, it runs on (and blocks) the RCU thread */
+#define rcu_call(func, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ void (*fptype)(typeof(ptr)); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_CALL, \
+ .u.call = { \
+ .fptr = (void *)func, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ (void)(_fptype = func); \
+ rcu_enqueue(_rcu_head, &_rcu_action); \
+ } while (0)
+
+extern void rcu_close(struct rcu_head_close *head, int fd);
+
+#endif /* _FRRCU_H */
diff --git a/lib/frrstr.c b/lib/frrstr.c
index c575c0b568..8a72a35af0 100644
--- a/lib/frrstr.c
+++ b/lib/frrstr.c
@@ -209,7 +209,7 @@ bool frrstr_endswith(const char *str, const char *suffix)
int all_digit(const char *str)
{
for (; *str != '\0'; str++)
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return 0;
return 1;
}
diff --git a/lib/if.c b/lib/if.c
index f7a167f251..9ee2f02e62 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -132,18 +132,26 @@ static int if_cmp_index_func(const struct interface *ifp1,
}
/* Create new interface structure. */
-struct interface *if_create(const char *name, vrf_id_t vrf_id)
+static struct interface *if_create_backend(const char *name, ifindex_t ifindex,
+ vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_get(vrf_id, NULL);
struct interface *ifp;
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
- ifp->ifindex = IFINDEX_INTERNAL;
-
- assert(name);
- strlcpy(ifp->name, name, sizeof(ifp->name));
ifp->vrf_id = vrf_id;
- IFNAME_RB_INSERT(vrf, ifp);
+
+ if (name) {
+ strlcpy(ifp->name, name, sizeof(ifp->name));
+ IFNAME_RB_INSERT(vrf, ifp);
+ } else
+ ifp->name[0] = '\0';
+
+ if (ifindex != IFINDEX_INTERNAL)
+ if_set_index(ifp, ifindex);
+ else
+ ifp->ifindex = ifindex; /* doesn't add it to the list */
+
ifp->connected = list_new();
ifp->connected->del = (void (*)(void *))connected_free;
@@ -158,6 +166,16 @@ struct interface *if_create(const char *name, vrf_id_t vrf_id)
return ifp;
}
+struct interface *if_create(const char *name, vrf_id_t vrf_id)
+{
+ return if_create_backend(name, IFINDEX_INTERNAL, vrf_id);
+}
+
+struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ return if_create_backend(NULL, ifindex, vrf_id);
+}
+
/* Create new interface structure. */
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
{
@@ -302,6 +320,23 @@ struct interface *if_lookup_by_name_all_vrf(const char *name)
return NULL;
}
+struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ if (ifindex == IFINDEX_INTERNAL)
+ return NULL;
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
+ if (ifp)
+ return ifp;
+ }
+
+ return NULL;
+}
+
/* Lookup interface by IPv4 address. */
struct interface *if_lookup_exact_address(void *src, int family,
vrf_id_t vrf_id)
@@ -447,6 +482,34 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
return NULL;
}
+struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ switch (vrf_get_backend()) {
+ case VRF_BACKEND_UNKNOWN:
+ case VRF_BACKEND_NETNS:
+ ifp = if_lookup_by_index(ifindex, vrf_id);
+ if (ifp)
+ return ifp;
+ return if_create_ifindex(ifindex, vrf_id);
+ case VRF_BACKEND_VRF_LITE:
+ ifp = if_lookup_by_index_all_vrf(ifindex);
+ if (ifp) {
+ if (ifp->vrf_id == vrf_id)
+ return ifp;
+ /* If it came from the kernel or by way of zclient,
+ * believe it and update the ifp accordingly.
+ */
+ if_update_to_new_vrf(ifp, vrf_id);
+ return ifp;
+ }
+ return if_create_ifindex(ifindex, vrf_id);
+ }
+
+ return NULL;
+}
+
void if_set_index(struct interface *ifp, ifindex_t ifindex)
{
struct vrf *vrf;
diff --git a/lib/if.h b/lib/if.h
index 603c9c3780..871e319f29 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -478,7 +478,9 @@ extern int if_cmp_name_func(const char *p1, const char *p2);
*/
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_create(const char *name, vrf_id_t vrf_id);
+extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
+extern struct interface *if_lookup_by_index_all_vrf(ifindex_t);
extern struct interface *if_lookup_exact_address(void *matchaddr, int family,
vrf_id_t vrf_id);
extern struct connected *if_lookup_address(void *matchaddr, int family,
@@ -493,6 +495,7 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
+extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
/* Delete the interface, but do not free the structure, and leave it in the
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 3294a61295..4301dc20ad 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -41,6 +41,7 @@
#include "northbound_cli.h"
#include "northbound_db.h"
#include "debug.h"
+#include "frrcu.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -409,7 +410,7 @@ static int frr_opt(int opt)
}
if (di->zpathspace)
fprintf(stderr,
- "-N option overriden by -z for zebra named socket path\n");
+ "-N option overridden by -z for zebra named socket path\n");
if (strchr(optarg, '/') || strchr(optarg, '.')) {
fprintf(stderr,
@@ -681,6 +682,7 @@ struct thread_master *frr_init(void)
log_filter_cmd_init();
log_ref_init();
+ log_ref_vty_init();
lib_error_init();
yang_init();
@@ -1080,6 +1082,7 @@ void frr_fini(void)
master = NULL;
closezlog();
/* frrmod_init -> nothing needed / hooks */
+ rcu_shutdown();
if (!debug_memstats_at_exit)
return;
diff --git a/lib/log.c b/lib/log.c
index 48ee0f6adb..51a0ddd6b7 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -387,10 +387,8 @@ void vzlog(int priority, const char *format, va_list args)
/* If it doesn't match on a filter, do nothing with the debug log */
if ((priority == LOG_DEBUG) && zlog_filter_count
- && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) {
- pthread_mutex_unlock(&loglock);
+ && vzlog_filter(zl, &tsctl, proto_str, priority, msg))
goto out;
- }
/* call external hook */
hook_call(zebra_ext_log, priority, format, args);
@@ -561,9 +559,7 @@ static void crash_write(struct fbuf *fb, char *msgstart)
void zlog_signal(int signo, const char *action, void *siginfo_v,
void *program_counter)
{
-#ifdef SA_SIGINFO
siginfo_t *siginfo = siginfo_v;
-#endif
time_t now;
char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
+ 100];
@@ -577,7 +573,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v,
msgstart = fb.pos;
bprintfrr(&fb, "Received signal %d at %lld", signo, (long long)now);
-#ifdef SA_SIGINFO
if (program_counter)
bprintfrr(&fb, " (si_addr 0x%tx, PC 0x%tx)",
(ptrdiff_t)siginfo->si_addr,
@@ -585,7 +580,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v,
else
bprintfrr(&fb, " (si_addr 0x%tx)",
(ptrdiff_t)siginfo->si_addr);
-#endif /* SA_SIGINFO */
bprintfrr(&fb, "; %s\n", action);
crash_write(&fb, msgstart);
@@ -1271,6 +1265,7 @@ void zlog_hexdump(const void *mem, unsigned int len)
size_t bs = ((len / 8) + 1) * 53 + 1;
char buf[bs];
char *s = buf;
+ const unsigned char *memch = mem;
memset(buf, 0, sizeof(buf));
@@ -1279,12 +1274,11 @@ void zlog_hexdump(const void *mem, unsigned int len)
/* print offset */
if (i % columns == 0)
s += snprintf(s, bs - (s - buf),
- "0x%016lx: ", (unsigned long)mem + i);
+ "0x%016lx: ", (unsigned long)memch + i);
/* print hex data */
if (i < len)
- s += snprintf(s, bs - (s - buf), "%02x ",
- 0xFF & ((const char *)mem)[i]);
+ s += snprintf(s, bs - (s - buf), "%02x ", memch[i]);
/* end of block, just aligning for ASCII dump */
else
@@ -1296,10 +1290,9 @@ void zlog_hexdump(const void *mem, unsigned int len)
/* end of block not really printing */
if (j >= len)
s += snprintf(s, bs - (s - buf), " ");
- else if (isprint((int)((const char *)mem)[j]))
- s += snprintf(
- s, bs - (s - buf), "%c",
- 0xFF & ((const char *)mem)[j]);
+ else if (isprint(memch[j]))
+ s += snprintf(s, bs - (s - buf), "%c",
+ memch[j]);
else /* other char */
s += snprintf(s, bs - (s - buf), ".");
}
diff --git a/lib/logicalrouter.c b/lib/logicalrouter.c
deleted file mode 100644
index da69ae5312..0000000000
--- a/lib/logicalrouter.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Logical Router functions.
- * Copyright (C) 2018 6WIND S.A.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "ns.h"
-#include "log.h"
-#include "memory.h"
-
-#include "command.h"
-#include "vty.h"
-#include "logicalrouter.h"
-
-/* Comment that useless define to avoid compilation error
- * in order to use it, one could provide the kind of NETNS to NS backend
- * so that the allocation will match the logical router
- * DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER, "LogicalRouter Context")
- */
-DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER_NAME, "Logical Router Name")
-
-/* Logical Router node has no interface. */
-static struct cmd_node logicalrouter_node = {LOGICALROUTER_NODE, "", 1};
-
-static int logicalrouter_backend;
-
-/* Get a NS. If not found, create one. */
-static struct ns *logicalrouter_get(ns_id_t ns_id)
-{
- struct ns *ns;
-
- ns = ns_lookup(ns_id);
- if (ns)
- return (ns);
- ns = ns_get_created(ns, NULL, ns_id);
- return ns;
-}
-
-static int logicalrouter_is_backend_netns(void)
-{
- return (logicalrouter_backend == LOGICALROUTER_BACKEND_NETNS);
-}
-
-
-DEFUN_NOSH (logicalrouter,
- logicalrouter_cmd,
- "logical-router (1-65535) ns NAME",
- "Enable a logical-router\n"
- "Specify the logical-router indentifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-{
- int idx_number = 1;
- int idx_name = 3;
- ns_id_t ns_id;
- struct ns *ns = NULL;
- char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
-
- if (!pathname)
- return CMD_WARNING_CONFIG_FAILED;
-
- ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
- ns = logicalrouter_get(ns_id);
-
- if (ns->name && strcmp(ns->name, pathname) != 0) {
- vty_out(vty, "NS %u is already configured with NETNS %s\n",
- ns->ns_id, ns->name);
- return CMD_WARNING;
- }
-
- if (!ns->name)
- ns->name = XSTRDUP(MTYPE_LOGICALROUTER_NAME, pathname);
-
- if (!ns_enable(ns, NULL)) {
- vty_out(vty, "Can not associate NS %u with NETNS %s\n",
- ns->ns_id, ns->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_logicalrouter,
- no_logicalrouter_cmd,
- "no logical-router (1-65535) ns NAME",
- NO_STR
- "Enable a Logical-Router\n"
- "Specify the Logical-Router identifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-{
- int idx_number = 2;
- int idx_name = 4;
- ns_id_t ns_id;
- struct ns *ns = NULL;
- char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
-
- if (!pathname)
- return CMD_WARNING_CONFIG_FAILED;
-
- ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
- ns = ns_lookup(ns_id);
-
- if (!ns) {
- vty_out(vty, "NS %u is not found\n", ns_id);
- return CMD_SUCCESS;
- }
-
- if (ns->name && strcmp(ns->name, pathname) != 0) {
- vty_out(vty, "Incorrect NETNS file name\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ns_disable(ns);
-
- if (ns->name) {
- XFREE(MTYPE_LOGICALROUTER_NAME, ns->name);
- ns->name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-/* Initialize NS module. */
-void logicalrouter_init(int (*writefunc)(struct vty *vty))
-{
- if (ns_have_netns() && logicalrouter_is_backend_netns()) {
- /* Install LogicalRouter commands. */
- install_node(&logicalrouter_node, writefunc);
- install_element(CONFIG_NODE, &logicalrouter_cmd);
- install_element(CONFIG_NODE, &no_logicalrouter_cmd);
- }
-}
-
-void logicalrouter_terminate(void)
-{
- ns_terminate();
-}
-
-void logicalrouter_configure_backend(int backend_netns)
-{
- logicalrouter_backend = backend_netns;
-}
diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h
deleted file mode 100644
index d18832ef70..0000000000
--- a/lib/logicalrouter.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Logical Router related header.
- * Copyright (C) 2018 6WIND S.A.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_LOGICAL_ROUTER_H
-#define _ZEBRA_LOGICAL_ROUTER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Logical Router Backend defines */
-#define LOGICALROUTER_BACKEND_OFF 0
-#define LOGICALROUTER_BACKEND_NETNS 1
-
-/*
- * Logical Router initializer/destructor
- */
-extern void logicalrouter_init(int (*writefunc)(struct vty *vty));
-extern void logicalrouter_terminate(void);
-
-/* used to configure backend for logical router
- * Currently, the whole NETNS feature is exclusively shared
- * between logical router and VRF backend NETNS
- * However, when logical router feature will be available,
- * one can think of having exclusivity only per NETNS
- */
-extern void logicalrouter_configure_backend(int backend_netns);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*_ZEBRA_LOGICAL_ROUTER_H*/
diff --git a/lib/netns_other.c b/lib/netns_other.c
index 4c7be05fab..b0aae4f8df 100644
--- a/lib/netns_other.c
+++ b/lib/netns_other.c
@@ -82,7 +82,7 @@ const char *ns_get_name(struct ns *ns)
}
/* only called from vrf ( when removing netns from vrf)
- * or at VRF or logical router termination
+ * or at VRF termination
*/
void ns_delete(struct ns *ns)
{
diff --git a/lib/ns.h b/lib/ns.h
index f3ad837889..1963b8a359 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -41,7 +41,7 @@ typedef uint32_t ns_id_t;
#ifdef HAVE_NETNS
#define NS_DEFAULT_NAME "/proc/self/ns/net"
#else /* !HAVE_NETNS */
-#define NS_DEFAULT_NAME "Default-logical-router"
+#define NS_DEFAULT_NAME "default-netns"
#endif /* HAVE_NETNS */
struct ns {
@@ -82,10 +82,10 @@ extern struct ns_head ns_tree;
* NS hooks
*/
-#define NS_NEW_HOOK 0 /* a new logical-router is just created */
-#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */
-#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */
-#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */
+#define NS_NEW_HOOK 0 /* a new netns is just created */
+#define NS_DELETE_HOOK 1 /* a netns is to be deleted */
+#define NS_ENABLE_HOOK 2 /* a netns is ready to use */
+#define NS_DISABLE_HOOK 3 /* a netns is to be unusable */
/*
* Add a specific hook ns module.
@@ -128,7 +128,7 @@ extern void ns_walk_func(int (*func)(struct ns *));
extern const char *ns_get_name(struct ns *ns);
/* only called from vrf ( when removing netns from vrf)
- * or at VRF or logical router termination
+ * or at VRF termination
*/
extern void ns_delete(struct ns *ns);
diff --git a/lib/plist.c b/lib/plist.c
index 1ba8982499..64571a05b7 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -218,7 +218,7 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
diff --git a/lib/pqueue.c b/lib/pqueue.c
deleted file mode 100644
index 87b54a681a..0000000000
--- a/lib/pqueue.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Priority queue functions.
- * Copyright (C) 2003 Yasuhiro Ohara
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "memory.h"
-#include "pqueue.h"
-
-DEFINE_MTYPE_STATIC(LIB, PQUEUE, "Priority queue")
-DEFINE_MTYPE_STATIC(LIB, PQUEUE_DATA, "Priority queue data")
-
-/* priority queue using heap sort */
-
-/* pqueue->cmp() controls the order of sorting (i.e, ascending or
- descending). If you want the left node to move upper of the heap
- binary tree, make cmp() to return less than 0. for example, if cmp
- (10, 20) returns -1, the sorting is ascending order. if cmp (10,
- 20) returns 1, the sorting is descending order. if cmp (10, 20)
- returns 0, this library does not do sorting (which will not be what
- you want). To be brief, if the contents of cmp_func (left, right)
- is left - right, dequeue () returns the smallest node. Otherwise
- (if the contents is right - left), dequeue () returns the largest
- node. */
-
-#define DATA_SIZE (sizeof (void *))
-#define PARENT_OF(x) ((x - 1) / 2)
-#define LEFT_OF(x) (2 * x + 1)
-#define RIGHT_OF(x) (2 * x + 2)
-#define HAVE_CHILD(x,q) (x < (q)->size / 2)
-
-void trickle_up(int index, struct pqueue *queue)
-{
- void *tmp;
-
- /* Save current node as tmp node. */
- tmp = queue->array[index];
-
- /* Continue until the node reaches top or the place where the parent
- node should be upper than the tmp node. */
- while (index > 0
- && (*queue->cmp)(tmp, queue->array[PARENT_OF(index)]) < 0) {
- /* actually trickle up */
- queue->array[index] = queue->array[PARENT_OF(index)];
- if (queue->update != NULL)
- (*queue->update)(queue->array[index], index);
- index = PARENT_OF(index);
- }
-
- /* Restore the tmp node to appropriate place. */
- queue->array[index] = tmp;
- if (queue->update != NULL)
- (*queue->update)(tmp, index);
-}
-
-void trickle_down(int index, struct pqueue *queue)
-{
- void *tmp;
- int which;
-
- /* Save current node as tmp node. */
- tmp = queue->array[index];
-
- /* Continue until the node have at least one (left) child. */
- while (HAVE_CHILD(index, queue)) {
- /* If right child exists, and if the right child is more proper
- to be moved upper. */
- if (RIGHT_OF(index) < queue->size
- && (*queue->cmp)(queue->array[LEFT_OF(index)],
- queue->array[RIGHT_OF(index)])
- > 0)
- which = RIGHT_OF(index);
- else
- which = LEFT_OF(index);
-
- /* If the tmp node should be upper than the child, break. */
- if ((*queue->cmp)(queue->array[which], tmp) > 0)
- break;
-
- /* Actually trickle down the tmp node. */
- queue->array[index] = queue->array[which];
- if (queue->update != NULL)
- (*queue->update)(queue->array[index], index);
- index = which;
- }
-
- /* Restore the tmp node to appropriate place. */
- queue->array[index] = tmp;
- if (queue->update != NULL)
- (*queue->update)(tmp, index);
-}
-
-struct pqueue *pqueue_create(void)
-{
- struct pqueue *queue;
-
- queue = XCALLOC(MTYPE_PQUEUE, sizeof(struct pqueue));
-
- queue->array =
- XCALLOC(MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE);
- queue->array_size = PQUEUE_INIT_ARRAYSIZE;
-
- /* By default we want nothing to happen when a node changes. */
- queue->update = NULL;
- return queue;
-}
-
-void pqueue_delete(struct pqueue *queue)
-{
- XFREE(MTYPE_PQUEUE_DATA, queue->array);
- XFREE(MTYPE_PQUEUE, queue);
-}
-
-static int pqueue_expand(struct pqueue *queue)
-{
- void **newarray;
-
- newarray =
- XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
-
- memcpy(newarray, queue->array, queue->array_size * DATA_SIZE);
-
- XFREE(MTYPE_PQUEUE_DATA, queue->array);
- queue->array = newarray;
- queue->array_size *= 2;
-
- return 1;
-}
-
-void pqueue_enqueue(void *data, struct pqueue *queue)
-{
- if (queue->size + 2 >= queue->array_size && !pqueue_expand(queue))
- return;
-
- queue->array[queue->size] = data;
- if (queue->update != NULL)
- (*queue->update)(data, queue->size);
- trickle_up(queue->size, queue);
- queue->size++;
-}
-
-void *pqueue_dequeue(struct pqueue *queue)
-{
- void *data = queue->array[0];
- queue->array[0] = queue->array[--queue->size];
- trickle_down(0, queue);
- return data;
-}
-
-void pqueue_remove_at(int index, struct pqueue *queue)
-{
- queue->array[index] = queue->array[--queue->size];
-
- if (index > 0
- && (*queue->cmp)(queue->array[index],
- queue->array[PARENT_OF(index)])
- < 0) {
- trickle_up(index, queue);
- } else {
- trickle_down(index, queue);
- }
-}
-
-void pqueue_remove(void *data, struct pqueue *queue)
-{
- for (int i = 0; i < queue->size; i++)
- if (queue->array[i] == data)
- pqueue_remove_at(i, queue);
-}
diff --git a/lib/pqueue.h b/lib/pqueue.h
deleted file mode 100644
index 032ee9db4c..0000000000
--- a/lib/pqueue.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Priority queue functions.
- * Copyright (C) 2003 Yasuhiro Ohara
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_PQUEUE_H
-#define _ZEBRA_PQUEUE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct pqueue {
- void **array;
- int array_size;
- int size;
-
- int (*cmp)(void *, void *);
- void (*update)(void *node, int actual_position);
-};
-
-#define PQUEUE_INIT_ARRAYSIZE 32
-
-extern struct pqueue *pqueue_create(void);
-extern void pqueue_delete(struct pqueue *queue);
-
-extern void pqueue_enqueue(void *data, struct pqueue *queue);
-extern void *pqueue_dequeue(struct pqueue *queue);
-extern void pqueue_remove_at(int index, struct pqueue *queue);
-extern void pqueue_remove(void *data, struct pqueue *queue);
-
-extern void trickle_down(int index, struct pqueue *queue);
-extern void trickle_up(int index, struct pqueue *queue);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZEBRA_PQUEUE_H */
diff --git a/lib/prefix.c b/lib/prefix.c
index 7abeebcd09..1a4a914e05 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -628,8 +628,15 @@ int prefix_match_network_statement(const struct prefix *n,
return 1;
}
-void prefix_copy(struct prefix *dest, const struct prefix *src)
+#ifdef __clang_analyzer__
+#undef prefix_copy /* cf. prefix.h */
+#endif
+
+void prefix_copy(union prefixptr udest, union prefixconstptr usrc)
{
+ struct prefix *dest = udest.p;
+ const struct prefix *src = usrc.p;
+
dest->family = src->family;
dest->prefixlen = src->prefixlen;
@@ -674,8 +681,11 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
* the same. Note that this routine has the same return value sense
* as '==' (which is different from prefix_cmp).
*/
-int prefix_same(const struct prefix *p1, const struct prefix *p2)
+int prefix_same(union prefixconstptr up1, union prefixconstptr up2)
{
+ const struct prefix *p1 = up1.p;
+ const struct prefix *p2 = up2.p;
+
if ((p1 && !p2) || (!p1 && p2))
return 0;
@@ -712,57 +722,59 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
}
/*
- * Return 0 if the network prefixes represented by the struct prefix
- * arguments are the same prefix, and 1 otherwise. Network prefixes
- * are considered the same if the prefix lengths are equal and the
- * network parts are the same. Host bits (which are considered masked
+ * Return -1/0/1 comparing the prefixes in a way that gives a full/linear
+ * order.
+ *
+ * Network prefixes are considered the same if the prefix lengths are equal
+ * and the network parts are the same. Host bits (which are considered masked
* by the prefix length) are not significant. Thus, 10.0.0.1/8 and
* 10.0.0.2/8 are considered equivalent by this routine. Note that
* this routine has the same return sense as strcmp (which is different
* from prefix_same).
*/
-int prefix_cmp(const struct prefix *p1, const struct prefix *p2)
+int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2)
{
+ const struct prefix *p1 = up1.p;
+ const struct prefix *p2 = up2.p;
int offset;
int shift;
+ int i;
/* Set both prefix's head pointer. */
const uint8_t *pp1;
const uint8_t *pp2;
if (p1->family != p2->family)
- return 1;
+ return numcmp(p1->family, p2->family);
if (p1->family == AF_FLOWSPEC) {
pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr;
pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr;
if (p1->u.prefix_flowspec.prefixlen !=
p2->u.prefix_flowspec.prefixlen)
- return 1;
+ return numcmp(p1->u.prefix_flowspec.prefixlen,
+ p2->u.prefix_flowspec.prefixlen);
offset = p1->u.prefix_flowspec.prefixlen;
while (offset--)
if (pp1[offset] != pp2[offset])
- return 1;
+ return numcmp(pp1[offset], pp2[offset]);
return 0;
}
pp1 = p1->u.val;
pp2 = p2->u.val;
if (p1->prefixlen != p2->prefixlen)
- return 1;
+ return numcmp(p1->prefixlen, p2->prefixlen);
offset = p1->prefixlen / PNBBY;
shift = p1->prefixlen % PNBBY;
- if (shift)
- if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
- return 1;
-
- while (offset--)
- if (pp1[offset] != pp2[offset])
- return 1;
+ i = memcmp(pp1, pp2, offset);
+ if (i)
+ return i;
- return 0;
+ return numcmp(pp1[offset] & maskbit[shift],
+ pp2[offset] & maskbit[shift]);
}
/*
diff --git a/lib/prefix.h b/lib/prefix.h
index d57b43dac6..e338140f1a 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -410,12 +410,20 @@ extern const char *prefix2str(union prefixconstptr, char *, int);
extern int prefix_match(const struct prefix *, const struct prefix *);
extern int prefix_match_network_statement(const struct prefix *,
const struct prefix *);
-extern int prefix_same(const struct prefix *, const struct prefix *);
-extern int prefix_cmp(const struct prefix *, const struct prefix *);
+extern int prefix_same(union prefixconstptr, union prefixconstptr);
+extern int prefix_cmp(union prefixconstptr, union prefixconstptr);
extern int prefix_common_bits(const struct prefix *, const struct prefix *);
-extern void prefix_copy(struct prefix *dest, const struct prefix *src);
+extern void prefix_copy(union prefixptr, union prefixconstptr);
extern void apply_mask(struct prefix *);
+#ifdef __clang_analyzer__
+/* clang-SA doesn't understand transparent unions, making it think that the
+ * target of prefix_copy is uninitialized. So just memset the target.
+ * cf. https://bugs.llvm.org/show_bug.cgi?id=42811
+ */
+#define prefix_copy(a, b) ({ memset(a, 0, sizeof(*a)); prefix_copy(a, b); })
+#endif
+
extern struct prefix *sockunion2prefix(const union sockunion *dest,
const union sockunion *mask);
extern struct prefix *sockunion2hostprefix(const union sockunion *,
diff --git a/lib/ptm_lib.c b/lib/ptm_lib.c
index 7f868beda4..a2ce9a0e2f 100644
--- a/lib/ptm_lib.c
+++ b/lib/ptm_lib.c
@@ -125,7 +125,7 @@ static int _ptm_lib_decode_header(csv_t *csv, int *msglen, int *version,
}
/* remove leading spaces */
for (i = j = 0; i < csv_field_len(fld); i++) {
- if (!isspace((int)hdr[i])) {
+ if (!isspace((unsigned char)hdr[i])) {
client_name[j] = hdr[i];
j++;
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 2fee3a479e..eca02e8366 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -927,15 +927,15 @@ static const char *route_map_type_str(enum route_map_type type)
return "";
}
-static const char *route_map_result_str(route_map_result_t res)
+static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
{
switch (res) {
case RMAP_MATCH:
return "match";
- case RMAP_DENYMATCH:
- return "deny";
case RMAP_NOMATCH:
return "no match";
+ case RMAP_NOOP:
+ return "noop";
case RMAP_ERROR:
return "error";
case RMAP_OKAY:
@@ -945,6 +945,18 @@ static const char *route_map_result_str(route_map_result_t res)
return "invalid";
}
+static const char *route_map_result_str(route_map_result_t res)
+{
+ switch (res) {
+ case RMAP_DENYMATCH:
+ return "deny";
+ case RMAP_PERMITMATCH:
+ return "permit";
+ }
+
+ return "invalid";
+}
+
static int route_map_empty(struct route_map *map)
{
if (map->head == NULL && map->tail == NULL)
@@ -1558,20 +1570,98 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
return 1;
}
+static enum route_map_cmd_result_t
+route_map_apply_match(struct route_map_rule_list *match_list,
+ const struct prefix *prefix, route_map_object_t type,
+ void *object)
+{
+ enum route_map_cmd_result_t ret = RMAP_NOMATCH;
+ struct route_map_rule *match;
+ bool is_matched = false;
+
+
+ /* Check all match rule and if there is no match rule, go to the
+ set statement. */
+ if (!match_list->head)
+ ret = RMAP_MATCH;
+ else {
+ for (match = match_list->head; match; match = match->next) {
+ /*
+ * Try each match statement. If any match does not
+ * return RMAP_MATCH or RMAP_NOOP, return.
+ * Otherwise continue on to next match statement.
+ * All match statements must MATCH for
+ * end-result to be a match.
+ * (Exception:If match stmts result in a mix of
+ * MATCH/NOOP, then also end-result is a match)
+ * If all result in NOOP, end-result is NOOP.
+ */
+ ret = (*match->cmd->func_apply)(match->value, prefix,
+ type, object);
+
+ /*
+ * If the consolidated result of func_apply is:
+ * -----------------------------------------------
+ * | MATCH | NOMATCH | NOOP | Final Result |
+ * ------------------------------------------------
+ * | yes | yes | yes | NOMATCH |
+ * | no | no | yes | NOOP |
+ * | yes | no | yes | MATCH |
+ * | no | yes | yes | NOMATCH |
+ * |-----------------------------------------------
+ *
+ * Traditionally, all rules within route-map
+ * should match for it to MATCH.
+ * If there are noops within the route-map rules,
+ * it follows the above matrix.
+ *
+ * Eg: route-map rm1 permit 10
+ * match rule1
+ * match rule2
+ * match rule3
+ * ....
+ * route-map rm1 permit 20
+ * match ruleX
+ * match ruleY
+ * ...
+ */
+
+ switch (ret) {
+ case RMAP_MATCH:
+ is_matched = true;
+ break;
+
+ case RMAP_NOMATCH:
+ return ret;
+
+ case RMAP_NOOP:
+ if (is_matched)
+ ret = RMAP_MATCH;
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ }
+ return ret;
+}
+
/* Apply route map's each index to the object.
The matrix for a route-map looks like this:
(note, this includes the description for the "NEXT"
and "GOTO" frobs now
- Match | No Match
- |
- permit action | cont
- |
- ------------------+---------------
- |
- deny deny | cont
- |
+ | Match | No Match | No op
+ |-----------|--------------|-------
+ permit | action | cont | cont.
+ | | default:deny | default:permit
+ -------------------+-----------------------
+ | deny | cont | cont.
+ deny | | default:deny | default:permit
+ |-----------|--------------|--------
action)
-Apply Set statements, accept route
@@ -1604,45 +1694,13 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
We need to make sure our route-map processing matches the above
*/
-
-static route_map_result_t
-route_map_apply_match(struct route_map_rule_list *match_list,
- const struct prefix *prefix, route_map_object_t type,
- void *object)
-{
- route_map_result_t ret = RMAP_NOMATCH;
- struct route_map_rule *match;
-
-
- /* Check all match rule and if there is no match rule, go to the
- set statement. */
- if (!match_list->head)
- ret = RMAP_MATCH;
- else {
- for (match = match_list->head; match; match = match->next) {
- /* Try each match statement in turn, If any do not
- return
- RMAP_MATCH, return, otherwise continue on to next
- match
- statement. All match statements must match for
- end-result
- to be a match. */
- ret = (*match->cmd->func_apply)(match->value, prefix,
- type, object);
- if (ret != RMAP_MATCH)
- return ret;
- }
- }
- return ret;
-}
-
-/* Apply route map to the object. */
route_map_result_t route_map_apply(struct route_map *map,
const struct prefix *prefix,
route_map_object_t type, void *object)
{
static int recursion = 0;
- int ret = 0;
+ enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
struct route_map_index *index;
struct route_map_rule *set;
char buf[PREFIX_STRLEN];
@@ -1656,7 +1714,7 @@ route_map_result_t route_map_apply(struct route_map *map,
return RMAP_DENYMATCH;
}
- if (map == NULL) {
+ if (map == NULL || map->head == NULL) {
ret = RMAP_DENYMATCH;
goto route_map_apply_end;
}
@@ -1665,29 +1723,64 @@ route_map_result_t route_map_apply(struct route_map *map,
for (index = map->head; index; index = index->next) {
/* Apply this index. */
index->applied++;
- ret = route_map_apply_match(&index->match_list, prefix, type,
- object);
+ match_ret = route_map_apply_match(&index->match_list, prefix,
+ type, object);
if (rmap_debug) {
zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
map->name, index->pref,
prefix2str(prefix, buf, sizeof(buf)),
- route_map_result_str(ret));
+ route_map_cmd_result_str(match_ret));
}
/* Now we apply the matrix from above */
- if (ret == RMAP_NOMATCH)
- /* 'cont' from matrix - continue to next route-map
- * sequence */
+ if (match_ret == RMAP_NOOP)
+ /*
+ * Do not change the return value. Retain the previous
+ * return value. Previous values can be:
+ * 1)permitmatch (if a nomatch was never
+ * seen before in this route-map.)
+ * 2)denymatch (if a nomatch was seen earlier in one
+ * of the previous sequences)
+ */
+
+ /*
+ * 'cont' from matrix - continue to next route-map
+ * sequence
+ */
continue;
- else if (ret == RMAP_MATCH) {
+ else if (match_ret == RMAP_NOMATCH) {
+
+ /*
+ * The return value is now changed to denymatch.
+ * So from here on out, even if we see more noops,
+ * we retain this return value and return this
+ * eventually if there are no matches.
+ */
+ ret = RMAP_DENYMATCH;
+
+ /*
+ * 'cont' from matrix - continue to next route-map
+ * sequence
+ */
+ continue;
+ } else if (match_ret == RMAP_MATCH) {
if (index->type == RMAP_PERMIT)
/* 'action' */
{
+ /* Match succeeded, rmap is of type permit */
+ ret = RMAP_PERMITMATCH;
+
/* permit+match must execute sets */
for (set = index->set_list.head; set;
set = set->next)
- ret = (*set->cmd->func_apply)(
+ /*
+ * set cmds return RMAP_OKAY or
+ * RMAP_ERROR. We do not care if
+ * set succeeded or not. So, ignore
+ * return code.
+ */
+ (void) (*set->cmd->func_apply)(
set->value, prefix, type,
object);
@@ -1741,8 +1834,6 @@ route_map_result_t route_map_apply(struct route_map *map,
}
}
}
- /* Finally route-map does not match at all. */
- ret = RMAP_DENYMATCH;
route_map_apply_end:
if (rmap_debug) {
diff --git a/lib/routemap.h b/lib/routemap.h
index 90df1048ed..f9ad0f64a9 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -38,13 +38,35 @@ DECLARE_MTYPE(ROUTE_MAP_COMPILED)
enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
typedef enum {
- RMAP_MATCH,
RMAP_DENYMATCH,
- RMAP_NOMATCH,
- RMAP_ERROR,
- RMAP_OKAY
+ RMAP_PERMITMATCH
} route_map_result_t;
+/*
+ * Route-map match or set result "Eg: match evpn vni xx"
+ * route-map match cmd always returns match/nomatch/noop
+ * match--> found a match
+ * nomatch--> didnt find a match
+ * noop--> not applicable
+ * route-map set retuns okay/error
+ * okay --> set was successful
+ * error --> set was not successful
+ */
+enum route_map_cmd_result_t {
+ /*
+ * route-map match cmd results
+ */
+ RMAP_MATCH,
+ RMAP_NOMATCH,
+ RMAP_NOOP,
+ /*
+ * route-map set cmd results
+ */
+ RMAP_OKAY,
+ RMAP_ERROR
+};
+
+
typedef enum {
RMAP_RIP,
RMAP_RIPNG,
@@ -91,10 +113,10 @@ struct route_map_rule_cmd {
const char *str;
/* Function for value set or match. */
- route_map_result_t (*func_apply)(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object);
+ enum route_map_cmd_result_t (*func_apply)(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object);
/* Compile argument and return result as void *. */
void *(*func_compile)(const char *);
diff --git a/lib/seqlock.c b/lib/seqlock.c
index 223d14952c..c05ec19db4 100644
--- a/lib/seqlock.c
+++ b/lib/seqlock.c
@@ -25,6 +25,7 @@
#include "config.h"
#endif
+#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
@@ -35,44 +36,75 @@
#include "seqlock.h"
+/****************************************
+ * OS specific synchronization wrappers *
+ ****************************************/
+
+/*
+ * Linux: sys_futex()
+ */
#ifdef HAVE_SYNC_LINUX_FUTEX
-/* Linux-specific - sys_futex() */
#include <sys/syscall.h>
#include <linux/futex.h>
-static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
- void *addr2, int val3)
+static long sys_futex(void *addr1, int op, int val1,
+ const struct timespec *timeout, void *addr2, int val3)
{
return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}
#define wait_once(sqlo, val) \
sys_futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
+#define wait_time(sqlo, val, time, reltime) \
+ sys_futex((int *)&sqlo->pos, FUTEX_WAIT_BITSET, (int)val, time, \
+ NULL, ~0U)
#define wait_poke(sqlo) \
sys_futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
+/*
+ * OpenBSD: sys_futex(), almost the same as on Linux
+ */
#elif defined(HAVE_SYNC_OPENBSD_FUTEX)
-/* OpenBSD variant of the above. untested, not upstream in OpenBSD. */
#include <sys/syscall.h>
#include <sys/futex.h>
+#define TIME_RELATIVE 1
+
#define wait_once(sqlo, val) \
futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
+#define wait_time(sqlo, val, time, reltime) \
+ futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, reltime, NULL, 0)
#define wait_poke(sqlo) \
futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
+/*
+ * FreeBSD: _umtx_op()
+ */
#elif defined(HAVE_SYNC_UMTX_OP)
-/* FreeBSD-specific: umtx_op() */
#include <sys/umtx.h>
#define wait_once(sqlo, val) \
_umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val, NULL, NULL)
+static int wait_time(struct seqlock *sqlo, uint32_t val,
+ const struct timespec *abstime,
+ const struct timespec *reltime)
+{
+ struct _umtx_time t;
+ t._flags = UMTX_ABSTIME;
+ t._clockid = CLOCK_MONOTONIC;
+ memcpy(&t._timeout, abstime, sizeof(t._timeout));
+ return _umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val,
+ (void *)(uintptr_t) sizeof(t), &t);
+}
#define wait_poke(sqlo) \
_umtx_op((void *)&sqlo->pos, UMTX_OP_WAKE, INT_MAX, NULL, NULL)
-#else
-/* generic version. used on *BSD, Solaris and OSX.
+/*
+ * generic version. used on NetBSD, Solaris and OSX. really shitty.
*/
+#else
+
+#define TIME_ABS_REALTIME 1
#define wait_init(sqlo) do { \
pthread_mutex_init(&sqlo->lock, NULL); \
@@ -80,6 +112,9 @@ static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
} while (0)
#define wait_prep(sqlo) pthread_mutex_lock(&sqlo->lock)
#define wait_once(sqlo, val) pthread_cond_wait(&sqlo->wake, &sqlo->lock)
+#define wait_time(sqlo, val, time, reltime) \
+ pthread_cond_timedwait(&sqlo->wake, \
+ &sqlo->lock, time);
#define wait_done(sqlo) pthread_mutex_unlock(&sqlo->lock)
#define wait_poke(sqlo) do { \
pthread_mutex_lock(&sqlo->lock); \
@@ -103,18 +138,112 @@ void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val)
seqlock_assert_valid(val);
wait_prep(sqlo);
- while (1) {
- cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire);
- if (!(cur & 1))
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+
+ while (cur & SEQLOCK_HELD) {
+ cal = SEQLOCK_VAL(cur) - val - 1;
+ assert(cal < 0x40000000 || cal > 0xc0000000);
+ if (cal < 0x80000000)
break;
- cal = cur - val - 1;
+
+ if ((cur & SEQLOCK_WAITERS)
+ || atomic_compare_exchange_weak_explicit(
+ &sqlo->pos, &cur, cur | SEQLOCK_WAITERS,
+ memory_order_relaxed, memory_order_relaxed)) {
+ wait_once(sqlo, cur | SEQLOCK_WAITERS);
+ cur = atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed);
+ }
+ /* else: we failed to swap in cur because it just changed */
+ }
+ wait_done(sqlo);
+}
+
+bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val,
+ const struct timespec *abs_monotime_limit)
+{
+/*
+ * ABS_REALTIME - used on NetBSD, Solaris and OSX
+ */
+#if TIME_ABS_REALTIME
+#define time_arg1 &abs_rt
+#define time_arg2 NULL
+#define time_prep
+ struct timespec curmono, abs_rt;
+
+ clock_gettime(CLOCK_MONOTONIC, &curmono);
+ clock_gettime(CLOCK_REALTIME, &abs_rt);
+
+ abs_rt.tv_nsec += abs_monotime_limit->tv_nsec - curmono.tv_nsec;
+ if (abs_rt.tv_nsec < 0) {
+ abs_rt.tv_sec--;
+ abs_rt.tv_nsec += 1000000000;
+ } else if (abs_rt.tv_nsec >= 1000000000) {
+ abs_rt.tv_sec++;
+ abs_rt.tv_nsec -= 1000000000;
+ }
+ abs_rt.tv_sec += abs_monotime_limit->tv_sec - curmono.tv_sec;
+
+/*
+ * RELATIVE - used on OpenBSD (might get a patch to get absolute monotime)
+ */
+#elif TIME_RELATIVE
+ struct timespec reltime;
+
+#define time_arg1 abs_monotime_limit
+#define time_arg2 &reltime
+#define time_prep \
+ clock_gettime(CLOCK_MONOTONIC, &reltime); \
+ reltime.tv_sec = abs_monotime_limit.tv_sec - reltime.tv_sec; \
+ reltime.tv_nsec = abs_monotime_limit.tv_nsec - reltime.tv_nsec; \
+ if (reltime.tv_nsec < 0) { \
+ reltime.tv_sec--; \
+ reltime.tv_nsec += 1000000000; \
+ }
+/*
+ * FreeBSD & Linux: absolute time re. CLOCK_MONOTONIC
+ */
+#else
+#define time_arg1 abs_monotime_limit
+#define time_arg2 NULL
+#define time_prep
+#endif
+
+ bool ret = true;
+ seqlock_val_t cur, cal;
+
+ seqlock_assert_valid(val);
+
+ wait_prep(sqlo);
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+
+ while (cur & SEQLOCK_HELD) {
+ cal = SEQLOCK_VAL(cur) - val - 1;
assert(cal < 0x40000000 || cal > 0xc0000000);
if (cal < 0x80000000)
break;
- wait_once(sqlo, cur);
+ if ((cur & SEQLOCK_WAITERS)
+ || atomic_compare_exchange_weak_explicit(
+ &sqlo->pos, &cur, cur | SEQLOCK_WAITERS,
+ memory_order_relaxed, memory_order_relaxed)) {
+ int rv;
+
+ time_prep
+
+ rv = wait_time(sqlo, cur | SEQLOCK_WAITERS, time_arg1,
+ time_arg2);
+ if (rv) {
+ ret = false;
+ break;
+ }
+ cur = atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed);
+ }
}
wait_done(sqlo);
+
+ return ret;
}
bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val)
@@ -123,26 +252,32 @@ bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val)
seqlock_assert_valid(val);
- cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire);
- if (!(cur & 1))
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+ if (!(cur & SEQLOCK_HELD))
return 1;
- cur -= val;
+ cur = SEQLOCK_VAL(cur) - val - 1;
assert(cur < 0x40000000 || cur > 0xc0000000);
return cur < 0x80000000;
}
void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val)
{
+ seqlock_val_t prev;
+
seqlock_assert_valid(val);
- atomic_store_explicit(&sqlo->pos, val, memory_order_release);
- wait_poke(sqlo);
+ prev = atomic_exchange_explicit(&sqlo->pos, val, memory_order_relaxed);
+ if (prev & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
}
void seqlock_release(struct seqlock *sqlo)
{
- atomic_store_explicit(&sqlo->pos, 0, memory_order_release);
- wait_poke(sqlo);
+ seqlock_val_t prev;
+
+ prev = atomic_exchange_explicit(&sqlo->pos, 0, memory_order_relaxed);
+ if (prev & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
}
void seqlock_init(struct seqlock *sqlo)
@@ -154,14 +289,23 @@ void seqlock_init(struct seqlock *sqlo)
seqlock_val_t seqlock_cur(struct seqlock *sqlo)
{
- return atomic_load_explicit(&sqlo->pos, memory_order_acquire);
+ return SEQLOCK_VAL(atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed));
}
seqlock_val_t seqlock_bump(struct seqlock *sqlo)
{
- seqlock_val_t val;
+ seqlock_val_t val, cur;
+
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+ seqlock_assert_valid(cur);
+
+ do {
+ val = SEQLOCK_VAL(cur) + SEQLOCK_INCR;
+ } while (!atomic_compare_exchange_weak_explicit(&sqlo->pos, &cur, val,
+ memory_order_relaxed, memory_order_relaxed));
- val = atomic_fetch_add_explicit(&sqlo->pos, 2, memory_order_release);
- wait_poke(sqlo);
+ if (cur & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
return val;
}
diff --git a/lib/seqlock.h b/lib/seqlock.h
index eef05a4307..b551e3ffc4 100644
--- a/lib/seqlock.h
+++ b/lib/seqlock.h
@@ -54,12 +54,28 @@
*/
/* use sequentially increasing "ticket numbers". lowest bit will always
- * be 1 to have a 'cleared' indication (i.e., counts 1,3,5,7,etc. )
+ * be 1 to have a 'cleared' indication (i.e., counts 1,5,9,13,etc. )
+ * 2nd lowest bit is used to indicate we have waiters.
*/
typedef _Atomic uint32_t seqlock_ctr_t;
typedef uint32_t seqlock_val_t;
-#define seqlock_assert_valid(val) assert(val & 1)
+#define seqlock_assert_valid(val) assert((val) & SEQLOCK_HELD)
+/* NB: SEQLOCK_WAITERS is only allowed if SEQLOCK_HELD is also set; can't
+ * have waiters on an unheld seqlock
+ */
+#define SEQLOCK_HELD (1U << 0)
+#define SEQLOCK_WAITERS (1U << 1)
+#define SEQLOCK_VAL(n) ((n) & ~SEQLOCK_WAITERS)
+#define SEQLOCK_STARTVAL 1U
+#define SEQLOCK_INCR 4U
+
+/* TODO: originally, this was using "atomic_fetch_add", which is the reason
+ * bit 0 is used to indicate held state. With SEQLOCK_WAITERS added, there's
+ * no fetch_add anymore (cmpxchg loop instead), so we don't need to use bit 0
+ * for this anymore & can just special-case the value 0 for it and skip it in
+ * counting.
+ */
struct seqlock {
/* always used */
@@ -74,8 +90,16 @@ struct seqlock {
extern void seqlock_init(struct seqlock *sqlo);
-/* while (sqlo <= val) - wait until seqlock->pos > val, or seqlock unheld */
+/* basically: "while (sqlo <= val) wait();"
+ * returns when sqlo > val || !seqlock_held(sqlo)
+ */
extern void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val);
+
+/* same, but time-limited (limit is an absolute CLOCK_MONOTONIC value) */
+extern bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val,
+ const struct timespec *abs_monotime_limit);
+
+/* one-shot test, returns true if seqlock_wait would return immediately */
extern bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val);
static inline bool seqlock_held(struct seqlock *sqlo)
@@ -85,12 +109,20 @@ static inline bool seqlock_held(struct seqlock *sqlo)
/* sqlo - get seqlock position -- for the "counter" seqlock */
extern seqlock_val_t seqlock_cur(struct seqlock *sqlo);
-/* sqlo++ - note: like x++, returns previous value, before bumping */
+
+/* ++sqlo (but atomic & wakes waiters) - returns value that we bumped to.
+ *
+ * guarantees:
+ * - each seqlock_bump call bumps the position by exactly one SEQLOCK_INCR.
+ * There are no skipped/missed or multiple increments.
+ * - each return value is only returned from one seqlock_bump() call
+ */
extern seqlock_val_t seqlock_bump(struct seqlock *sqlo);
/* sqlo = val - can be used on held seqlock. */
extern void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val);
+
/* sqlo = ref - standard pattern: acquire relative to other seqlock */
static inline void seqlock_acquire(struct seqlock *sqlo, struct seqlock *ref)
{
diff --git a/lib/sigevent.c b/lib/sigevent.c
index d02b074223..fcd85d0d43 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -24,7 +24,6 @@
#include <memory.h>
#include <lib_errors.h>
-#ifdef SA_SIGINFO
#ifdef HAVE_UCONTEXT_H
#ifdef GNU_LINUX
/* get REG_EIP from ucontext.h */
@@ -34,7 +33,6 @@
#endif /* GNU_LINUX */
#include <ucontext.h>
#endif /* HAVE_UCONTEXT_H */
-#endif /* SA_SIGINFO */
/* master signals descriptor struct */
@@ -158,8 +156,6 @@ static int signal_set(int signo)
return 0;
}
-#ifdef SA_SIGINFO
-
/* XXX This function should be enhanced to support more platforms
(it currently works only on Linux/x86). */
static void *program_counter(void *context)
@@ -199,41 +195,19 @@ static void *program_counter(void *context)
return NULL;
}
-#endif /* SA_SIGINFO */
-
static void __attribute__((noreturn))
-exit_handler(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *context
-#endif
- )
+exit_handler(int signo, siginfo_t *siginfo, void *context)
{
-#ifndef SA_SIGINFO
- void *siginfo = NULL;
- void *pc = NULL;
-#else
void *pc = program_counter(context);
-#endif
zlog_signal(signo, "exiting...", siginfo, pc);
_exit(128 + signo);
}
static void __attribute__((noreturn))
-core_handler(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *context
-#endif
- )
+core_handler(int signo, siginfo_t *siginfo, void *context)
{
-#ifndef SA_SIGINFO
- void *siginfo = NULL;
- void *pc = NULL;
-#else
void *pc = program_counter(context);
-#endif
/* make sure we don't hang in here. default for SIGALRM is terminate.
* - if we're in backtrace for more than a second, abort. */
@@ -290,12 +264,7 @@ static void trap_default_signals(void)
static const struct {
const int *sigs;
unsigned int nsigs;
- void (*handler)(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *info, void *context
-#endif
- );
+ void (*handler)(int signo, siginfo_t *info, void *context);
} sigmap[] = {
{core_signals, array_size(core_signals), core_handler},
{exit_signals, array_size(exit_signals), exit_handler},
@@ -316,15 +285,10 @@ static void trap_default_signals(void)
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
} else {
-#ifdef SA_SIGINFO
/* Request extra arguments to signal
* handler. */
act.sa_sigaction = sigmap[i].handler;
act.sa_flags = SA_SIGINFO;
-#else
- act.sa_handler = sigmap[i].handler;
- act.sa_flags = 0;
-#endif
#ifdef SA_RESETHAND
/* don't try to print backtraces
* recursively */
diff --git a/lib/stream.c b/lib/stream.c
index 6c187bd359..c67bc3c993 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -904,20 +904,30 @@ int stream_put_prefix(struct stream *s, struct prefix *p)
/* Put NLRI with label */
int stream_put_labeled_prefix(struct stream *s, struct prefix *p,
- mpls_label_t *label)
+ mpls_label_t *label, int addpath_encode,
+ uint32_t addpath_tx_id)
{
size_t psize;
+ size_t psize_with_addpath;
uint8_t *label_pnt = (uint8_t *)label;
STREAM_VERIFY_SANE(s);
psize = PSIZE(p->prefixlen);
+ psize_with_addpath = psize + (addpath_encode ? 4 : 0);
- if (STREAM_WRITEABLE(s) < (psize + 3)) {
+ if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) {
STREAM_BOUND_WARN(s, "put");
return 0;
}
+ if (addpath_encode) {
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
+ s->data[s->endp++] = (uint8_t)addpath_tx_id;
+ }
+
stream_putc(s, (p->prefixlen + 24));
stream_putc(s, label_pnt[0]);
stream_putc(s, label_pnt[1]);
diff --git a/lib/stream.h b/lib/stream.h
index 5341bfa40b..a903ec0ea5 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -199,7 +199,8 @@ extern int stream_put_prefix_addpath(struct stream *, struct prefix *,
uint32_t addpath_tx_id);
extern int stream_put_prefix(struct stream *, struct prefix *);
extern int stream_put_labeled_prefix(struct stream *, struct prefix *,
- mpls_label_t *);
+ mpls_label_t *, int addpath_encode,
+ uint32_t addpath_tx_id);
extern void stream_get(void *, struct stream *, size_t);
extern bool stream_get2(void *data, struct stream *s, size_t size);
extern void stream_get_from(void *, struct stream *, size_t, size_t);
diff --git a/lib/subdir.am b/lib/subdir.am
index aa89622028..2be7537bcc 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -21,6 +21,7 @@ lib_libfrr_la_SOURCES = \
lib/distribute.c \
lib/ferr.c \
lib/filter.c \
+ lib/frrcu.c \
lib/frrlua.c \
lib/frr_pthread.c \
lib/frrstr.c \
@@ -61,7 +62,6 @@ lib_libfrr_la_SOURCES = \
lib/openbsd-tree.c \
lib/pid_output.c \
lib/plist.c \
- lib/pqueue.c \
lib/prefix.c \
lib/privs.c \
lib/ptm_lib.c \
@@ -95,7 +95,6 @@ lib_libfrr_la_SOURCES = \
lib/yang_translator.c \
lib/yang_wrappers.c \
lib/zclient.c \
- lib/logicalrouter.c \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
lib/printf/glue.c \
@@ -113,7 +112,6 @@ vtysh_scan += \
$(top_srcdir)/lib/if.c \
$(top_srcdir)/lib/if_rmap.c \
$(top_srcdir)/lib/keychain.c \
- $(top_srcdir)/lib/logicalrouter.c \
$(top_srcdir)/lib/nexthop_group.c \
$(top_srcdir)/lib/plist.c \
$(top_srcdir)/lib/routemap.c \
@@ -163,6 +161,7 @@ pkginclude_HEADERS += \
lib/frrlua.h \
lib/frr_pthread.h \
lib/frratomic.h \
+ lib/frrcu.h \
lib/frrstr.h \
lib/getopt.h \
lib/graph.h \
@@ -200,7 +199,6 @@ pkginclude_HEADERS += \
lib/openbsd-queue.h \
lib/openbsd-tree.h \
lib/plist.h \
- lib/pqueue.h \
lib/prefix.h \
lib/printfrr.h \
lib/privs.h \
@@ -241,7 +239,6 @@ pkginclude_HEADERS += \
lib/zassert.h \
lib/zclient.h \
lib/zebra.h \
- lib/logicalrouter.h \
lib/pbr.h \
# end
diff --git a/lib/thread.c b/lib/thread.c
index fc2de09df0..943b849ebf 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -25,9 +25,9 @@
#include "thread.h"
#include "memory.h"
+#include "frrcu.h"
#include "log.h"
#include "hash.h"
-#include "pqueue.h"
#include "command.h"
#include "sigevent.h"
#include "network.h"
@@ -42,6 +42,22 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
DECLARE_LIST(thread_list, struct thread, threaditem)
+static int thread_timer_cmp(const struct thread *a, const struct thread *b)
+{
+ if (a->u.sands.tv_sec < b->u.sands.tv_sec)
+ return -1;
+ if (a->u.sands.tv_sec > b->u.sands.tv_sec)
+ return 1;
+ if (a->u.sands.tv_usec < b->u.sands.tv_usec)
+ return -1;
+ if (a->u.sands.tv_usec > b->u.sands.tv_usec)
+ return 1;
+ return 0;
+}
+
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem,
+ thread_timer_cmp)
+
#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
@@ -401,25 +417,6 @@ void thread_cmd_init(void)
/* CLI end ------------------------------------------------------------------ */
-static int thread_timer_cmp(void *a, void *b)
-{
- struct thread *thread_a = a;
- struct thread *thread_b = b;
-
- if (timercmp(&thread_a->u.sands, &thread_b->u.sands, <))
- return -1;
- if (timercmp(&thread_a->u.sands, &thread_b->u.sands, >))
- return 1;
- return 0;
-}
-
-static void thread_timer_update(void *node, int actual_position)
-{
- struct thread *thread = node;
-
- thread->index = actual_position;
-}
-
static void cancelreq_del(void *cr)
{
XFREE(MTYPE_TMP, cr);
@@ -464,11 +461,7 @@ struct thread_master *thread_master_create(const char *name)
thread_list_init(&rv->event);
thread_list_init(&rv->ready);
thread_list_init(&rv->unuse);
-
- /* Initialize the timer queues */
- rv->timer = pqueue_create();
- rv->timer->cmp = thread_timer_cmp;
- rv->timer->update = thread_timer_update;
+ thread_timer_list_init(&rv->timer);
/* Initialize thread_fetch() settings */
rv->spin = true;
@@ -566,16 +559,6 @@ static void thread_array_free(struct thread_master *m,
XFREE(MTYPE_THREAD_POLL, thread_array);
}
-static void thread_queue_free(struct thread_master *m, struct pqueue *queue)
-{
- int i;
-
- for (i = 0; i < queue->size; i++)
- thread_free(m, queue->array[i]);
-
- pqueue_delete(queue);
-}
-
/*
* thread_master_free_unused
*
@@ -598,6 +581,8 @@ void thread_master_free_unused(struct thread_master *m)
/* Stop thread scheduler. */
void thread_master_free(struct thread_master *m)
{
+ struct thread *t;
+
pthread_mutex_lock(&masters_mtx);
{
listnode_delete(masters, m);
@@ -609,7 +594,8 @@ void thread_master_free(struct thread_master *m)
thread_array_free(m, m->read);
thread_array_free(m, m->write);
- thread_queue_free(m, m->timer);
+ while ((t = thread_timer_list_pop(&m->timer)))
+ thread_free(m, t);
thread_list_free(m, &m->event);
thread_list_free(m, &m->ready);
thread_list_free(m, &m->unuse);
@@ -683,7 +669,6 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type,
thread->add_type = type;
thread->master = m;
thread->arg = arg;
- thread->index = -1;
thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
thread->ref = NULL;
@@ -729,7 +714,7 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
{
/* If timer_wait is null here, that means poll() should block
* indefinitely,
- * unless the thread_master has overriden it by setting
+ * unless the thread_master has overridden it by setting
* ->selectpoll_timeout.
* If the value is positive, it specifies the maximum number of
* milliseconds
@@ -753,6 +738,9 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
< 0) // effect a poll (return immediately)
timeout = 0;
+ rcu_read_unlock();
+ rcu_assert_read_unlocked();
+
/* add poll pipe poker */
assert(count + 1 < pfdsize);
pfds[count].fd = m->io_pipe[0];
@@ -766,6 +754,8 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
;
+ rcu_read_lock();
+
return num;
}
@@ -854,7 +844,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
struct thread **t_ptr, debugargdef)
{
struct thread *thread;
- struct pqueue *queue;
assert(m != NULL);
@@ -870,7 +859,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
return NULL;
}
- queue = m->timer;
thread = thread_get(m, type, func, arg, debugargpass);
pthread_mutex_lock(&thread->mtx);
@@ -878,7 +866,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
monotime(&thread->u.sands);
timeradd(&thread->u.sands, time_relative,
&thread->u.sands);
- pqueue_enqueue(thread, queue);
+ thread_timer_list_add(&m->timer, thread);
if (t_ptr) {
*t_ptr = thread;
thread->ref = t_ptr;
@@ -1055,7 +1043,6 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
static void do_thread_cancel(struct thread_master *master)
{
struct thread_list_head *list = NULL;
- struct pqueue *queue = NULL;
struct thread **thread_array = NULL;
struct thread *thread;
@@ -1111,7 +1098,7 @@ static void do_thread_cancel(struct thread_master *master)
thread_array = master->write;
break;
case THREAD_TIMER:
- queue = master->timer;
+ thread_timer_list_del(&master->timer, thread);
break;
case THREAD_EVENT:
list = &master->event;
@@ -1124,16 +1111,10 @@ static void do_thread_cancel(struct thread_master *master)
break;
}
- if (queue) {
- assert(thread->index >= 0);
- assert(thread == queue->array[thread->index]);
- pqueue_remove_at(thread->index, queue);
- } else if (list) {
+ if (list) {
thread_list_del(list, thread);
} else if (thread_array) {
thread_array[thread->u.fd] = NULL;
- } else {
- assert(!"Thread should be either in queue or list or array!");
}
if (thread->ref)
@@ -1251,15 +1232,15 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread,
}
/* ------------------------------------------------------------------------- */
-static struct timeval *thread_timer_wait(struct pqueue *queue,
+static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers,
struct timeval *timer_val)
{
- if (queue->size) {
- struct thread *next_timer = queue->array[0];
- monotime_until(&next_timer->u.sands, timer_val);
- return timer_val;
- }
- return NULL;
+ if (!thread_timer_list_count(timers))
+ return NULL;
+
+ struct thread *next_timer = thread_timer_list_first(timers);
+ monotime_until(&next_timer->u.sands, timer_val);
+ return timer_val;
}
static struct thread *thread_run(struct thread_master *m, struct thread *thread,
@@ -1369,17 +1350,16 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
}
/* Add all timers that have popped to the ready list. */
-static unsigned int thread_process_timers(struct pqueue *queue,
+static unsigned int thread_process_timers(struct thread_timer_list_head *timers,
struct timeval *timenow)
{
struct thread *thread;
unsigned int ready = 0;
- while (queue->size) {
- thread = queue->array[0];
+ while ((thread = thread_timer_list_first(timers))) {
if (timercmp(timenow, &thread->u.sands, <))
return ready;
- pqueue_dequeue(queue);
+ thread_timer_list_pop(timers);
thread->type = THREAD_READY;
thread_list_add_tail(&thread->master->ready, thread);
ready++;
@@ -1461,7 +1441,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
* once per loop to avoid starvation by events
*/
if (!thread_list_count(&m->ready))
- tw = thread_timer_wait(m->timer, &tv);
+ tw = thread_timer_wait(&m->timer, &tv);
if (thread_list_count(&m->ready) ||
(tw && !timercmp(tw, &zerotime, >)))
@@ -1506,7 +1486,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
/* Post timers to ready queue. */
monotime(&now);
- thread_process_timers(m->timer, &now);
+ thread_process_timers(&m->timer, &now);
/* Post I/O to ready queue. */
if (num > 0)
diff --git a/lib/thread.h b/lib/thread.h
index 7897265120..412a4d93bf 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -41,8 +41,7 @@ struct rusage_t {
#define GETRUSAGE(X) thread_getrusage(X)
PREDECL_LIST(thread_list)
-
-struct pqueue;
+PREDECL_HEAP(thread_timer_list)
struct fd_handler {
/* number of pfd that fit in the allocated space of pfds. This is a
@@ -73,7 +72,7 @@ struct thread_master {
struct thread **read;
struct thread **write;
- struct pqueue *timer;
+ struct thread_timer_list_head timer;
struct thread_list_head event, ready, unuse;
struct list *cancel_req;
bool canceled;
@@ -95,6 +94,7 @@ struct thread {
uint8_t type; /* thread type */
uint8_t add_type; /* thread type */
struct thread_list_item threaditem;
+ struct thread_timer_list_item timeritem;
struct thread **ref; /* external reference (if given) */
struct thread_master *master; /* pointer to the struct thread_master */
int (*func)(struct thread *); /* event function */
@@ -104,7 +104,6 @@ struct thread {
int fd; /* file descriptor in case of r/w */
struct timeval sands; /* rest of time sands value. */
} u;
- int index; /* queue position for timers */
struct timeval real;
struct cpu_thread_history *hist; /* cache pointer to cpu_history */
unsigned long yield; /* yield time in microseconds */
diff --git a/lib/typerb.c b/lib/typerb.c
index 4c48d6434f..3886fc678e 100644
--- a/lib/typerb.c
+++ b/lib/typerb.c
@@ -333,9 +333,10 @@ color:
return (old);
}
-void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe)
+struct typed_rb_entry *typed_rb_remove(struct rbt_tree *rbt,
+ struct rb_entry *rbe)
{
- rbe_remove(rbt, rbe);
+ return rbe_remove(rbt, rbe);
}
struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt,
diff --git a/lib/typerb.h b/lib/typerb.h
index ce8446f853..2d7b0ba637 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -38,29 +38,30 @@ struct typed_rb_root {
size_t count;
};
-struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt,
struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe);
-struct typed_rb_entry *typed_rb_find(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt,
+ struct typed_rb_entry *rbe);
+struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_min(struct typed_rb_root *);
-struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *);
+struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt);
+struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
@@ -99,9 +100,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \
return container_of_null(re, type, field.re); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
- typed_rb_remove(&h->rr, &item->field.re); \
+ struct typed_rb_entry *re; \
+ re = typed_rb_remove(&h->rr, &item->field.re); \
+ return container_of_null(re, type, field.re); \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -130,7 +133,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
re = item ? typed_rb_next(&item->field.re) : NULL; \
return container_of_null(re, type, field.re); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->rr.count; \
} \
diff --git a/lib/typesafe.c b/lib/typesafe.c
index f2ca67b7c6..7e5939d5b3 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -341,13 +341,14 @@ struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
return best;
}
-void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
- int (*cmpfn)(const struct sskip_item *a,
- const struct sskip_item *b))
+struct sskip_item *typesafe_skiplist_del(
+ struct sskip_head *head, struct sskip_item *item,
+ int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b))
{
size_t level = SKIPLIST_MAXDEPTH;
struct sskip_item *prev = &head->hitem, *next;
int cmpval;
+ bool found = false;
while (level) {
next = sl_level_get(prev, level - 1);
@@ -359,6 +360,7 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
sl_level_set(prev, level - 1,
sl_level_get(item, level - 1));
level--;
+ found = true;
continue;
}
cmpval = cmpfn(next, item);
@@ -369,6 +371,9 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
level--;
}
+ if (!found)
+ return NULL;
+
/* TBD: assert when trying to remove non-existing item? */
head->count--;
@@ -379,6 +384,8 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
XFREE(MTYPE_SKIPLIST_OFLOW, oflow);
}
memset(item, 0, sizeof(*item));
+
+ return item;
}
struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head)
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 0a4ed69e4e..c30d73d1b3 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -109,17 +109,18 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
typesafe_list_add(&h->sh, nextp, &item->field.si); \
} \
/* TODO: del_hint */ \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct slist_item **iter = &h->sh.first; \
while (*iter && *iter != &item->field.si) \
iter = &(*iter)->next; \
if (!*iter) \
- return; \
+ return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
if (!item->field.si.next) \
h->sh.last_next = iter; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -149,7 +150,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -212,13 +213,14 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
prev = after ? &after->field.di : &h->dh.hitem; \
typesafe_dlist_add(&h->dh, prev, &item->field.di); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct dlist_item *ditem = &item->field.di; \
ditem->prev->next = ditem->next; \
ditem->next->prev = ditem->prev; \
h->dh.count--; \
ditem->prev = ditem->next = NULL; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -250,7 +252,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->dh.count; \
} \
@@ -308,7 +310,7 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
h->hh.count++; \
return NULL; \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct heap_item *other; \
uint32_t index = item->field.hi.index; \
@@ -321,6 +323,7 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
typesafe_heap_pushdown(&h->hh, index, other, prefix ## __cmp); \
if (HEAP_RESIZE_TRESH_DN(h)) \
typesafe_heap_resize(&h->hh, false); \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -354,7 +357,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
@@ -434,7 +437,7 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = sitem->next; \
return container_of_null(sitem, type, field.si); \
} \
@@ -444,20 +447,21 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
struct ssort_item *prev = NULL, *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = (prev = sitem)->next; \
return container_of_null(prev, type, field.si); \
} \
/* TODO: del_hint */ \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct ssort_item **iter = &h->sh.first; \
while (*iter && *iter != &item->field.si) \
iter = &(*iter)->next; \
if (!*iter) \
- return; \
+ return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -485,7 +489,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -499,7 +503,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = sitem->next; \
if (!sitem || cmpval > 0) \
return NULL; \
@@ -617,10 +621,10 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
} \
return NULL; \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
if (!h->hh.tabshift) \
- return; \
+ return NULL; \
uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \
struct thash_item **np = &h->hh.entries[hbits]; \
while (*np && (*np)->hashval < hval) \
@@ -628,12 +632,13 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
while (*np && *np != &item->field.hi && (*np)->hashval == hval) \
np = &(*np)->next; \
if (*np != &item->field.hi) \
- return; \
+ return NULL; \
*np = item->field.hi.next; \
item->field.hi.next = NULL; \
h->hh.count--; \
if (HASH_SHRINK_THRESHOLD(h->hh)) \
typesafe_hash_shrink(&h->hh); \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -675,7 +680,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
@@ -751,9 +756,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
&item->field.si, cmpfn_nuq); \
return container_of_null(sitem, type, field.si); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
- typesafe_skiplist_del(&h->sh, &item->field.si, cmpfn_uq); \
+ struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \
+ &item->field.si, cmpfn_uq); \
+ return container_of_null(sitem, type, field.si); \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -776,7 +783,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
next = item ? item->field.si.next[0] : NULL; \
return container_of_null(next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -848,8 +855,8 @@ extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
-extern void typesafe_skiplist_del(struct sskip_head *head,
- struct sskip_item *item, int (*cmpfn)(
+extern struct sskip_item *typesafe_skiplist_del(
+ struct sskip_head *head, struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head);
diff --git a/lib/vty.c b/lib/vty.c
index 18a449f647..c1535802cf 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -337,7 +337,8 @@ void vty_hello(struct vty *vty)
/* work backwards to ignore trailling isspace()
*/
for (s = buf + strlen(buf);
- (s > buf) && isspace((int)*(s - 1)); s--)
+ (s > buf) && isspace((unsigned char)s[-1]);
+ s--)
;
*s = '\0';
vty_out(vty, "%s\n", buf);
@@ -468,7 +469,7 @@ static int vty_command(struct vty *vty, char *buf)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
- while (isspace((int)*cp) && *cp != '\0')
+ while (isspace((unsigned char)*cp) && *cp != '\0')
cp++;
}
if (cp != NULL && *cp != '\0') {
@@ -892,7 +893,7 @@ static void vty_complete_command(struct vty *vty)
return;
/* In case of 'help \t'. */
- if (isspace((int)vty->buf[vty->length - 1]))
+ if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
matched = cmd_complete_command(vline, vty, &ret);
@@ -1006,7 +1007,7 @@ static void vty_describe_command(struct vty *vty)
if (vline == NULL) {
vline = vector_init(1);
vector_set(vline, NULL);
- } else if (isspace((int)vty->buf[vty->length - 1]))
+ } else if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
describe = cmd_describe_command(vline, vty, &ret);
diff --git a/lib/zebra.h b/lib/zebra.h
index 22239f8e60..789a93a3c4 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -134,6 +134,10 @@ typedef unsigned char uint8_t;
#endif
#endif
+#ifdef CRYPTO_OPENSSL
+#include <openssl/evp.h>
+#endif
+
#include "openbsd-tree.h"
#include <netinet/in.h>
@@ -356,6 +360,7 @@ typedef enum {
/* Subsequent Address Family Identifier. */
typedef enum {
+ SAFI_UNSPEC = 0,
SAFI_UNICAST = 1,
SAFI_MULTICAST = 2,
SAFI_MPLS_VPN = 3,