summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/bfd.c39
-rw-r--r--lib/bfd.h4
-rw-r--r--lib/bitfield.h43
-rw-r--r--lib/buffer.c3
-rw-r--r--lib/command.c10
-rw-r--r--lib/command.h36
-rw-r--r--lib/command_graph.h1
-rw-r--r--lib/defun_lex.l2
-rw-r--r--lib/ferr.c4
-rw-r--r--lib/filter.h5
-rw-r--r--lib/filter_cli.c267
-rw-r--r--lib/filter_nb.c451
-rw-r--r--lib/id_alloc.c11
-rw-r--r--lib/if.c25
-rw-r--r--lib/if.h7
-rw-r--r--lib/ipaddr.h64
-rw-r--r--lib/libfrr.c10
-rw-r--r--lib/linklist.c75
-rw-r--r--lib/linklist.h33
-rw-r--r--lib/log.c19
-rw-r--r--lib/log.h6
-rw-r--r--lib/memory.c3
-rw-r--r--lib/mpls.h1
-rw-r--r--lib/netns_linux.c38
-rw-r--r--lib/nexthop.c133
-rw-r--r--lib/nexthop.h29
-rw-r--r--lib/nexthop_group.c83
-rw-r--r--lib/nexthop_group.h6
-rw-r--r--lib/northbound.c51
-rw-r--r--lib/northbound.h26
-rw-r--r--lib/northbound_cli.c147
-rw-r--r--lib/northbound_cli.h8
-rw-r--r--lib/northbound_confd.c7
-rw-r--r--lib/northbound_grpc.cpp24
-rw-r--r--lib/northbound_sysrepo.c7
-rw-r--r--lib/ns.h16
-rw-r--r--lib/pbr.h7
-rw-r--r--lib/prefix.c21
-rw-r--r--lib/prefix.h62
-rw-r--r--lib/privs.c3
-rw-r--r--lib/privs.h1
-rwxr-xr-xlib/route_types.pl2
-rw-r--r--lib/route_types.txt1
-rw-r--r--lib/routemap.c89
-rw-r--r--lib/routemap.h16
-rw-r--r--lib/routemap_cli.c163
-rw-r--r--lib/routemap_northbound.c85
-rw-r--r--lib/routing_nb.c40
-rw-r--r--lib/routing_nb.h24
-rw-r--r--lib/routing_nb_config.c74
-rw-r--r--lib/sockopt.c6
-rw-r--r--lib/sockunion.c50
-rw-r--r--lib/sockunion.h4
-rw-r--r--lib/srcdest_table.c10
-rw-r--r--lib/srcdest_table.h2
-rw-r--r--lib/srte.h56
-rw-r--r--lib/stream.c72
-rw-r--r--lib/stream.h8
-rw-r--r--lib/subdir.am8
-rw-r--r--lib/thread.c113
-rw-r--r--lib/thread.h4
-rw-r--r--lib/vrf.c22
-rw-r--r--lib/vrf.h2
-rw-r--r--lib/vty.c9
-rw-r--r--lib/vty.h8
-rw-r--r--lib/yang.c172
-rw-r--r--lib/yang.h55
-rw-r--r--lib/yang_wrappers.c83
-rw-r--r--lib/yang_wrappers.h5
-rw-r--r--lib/zclient.c225
-rw-r--r--lib/zclient.h67
-rw-r--r--lib/zlog.c6
72 files changed, 2226 insertions, 1043 deletions
diff --git a/lib/bfd.c b/lib/bfd.c
index 7c84648d91..d1a0ec671e 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -94,7 +94,8 @@ int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str,
* bfd_set_param - Set the configured BFD paramter values
*/
void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
- uint8_t detect_mult, int defaults, int *command)
+ uint8_t detect_mult, const char *profile, int defaults,
+ int *command)
{
if (!*bfd_info) {
*bfd_info = bfd_info_create();
@@ -102,7 +103,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
} else {
if (((*bfd_info)->required_min_rx != min_rx)
|| ((*bfd_info)->desired_min_tx != min_tx)
- || ((*bfd_info)->detect_mult != detect_mult))
+ || ((*bfd_info)->detect_mult != detect_mult)
+ || (profile && strcmp((*bfd_info)->profile, profile)))
*command = ZEBRA_BFD_DEST_UPDATE;
}
@@ -110,6 +112,11 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
(*bfd_info)->required_min_rx = min_rx;
(*bfd_info)->desired_min_tx = min_tx;
(*bfd_info)->detect_mult = detect_mult;
+ if (profile)
+ strlcpy((*bfd_info)->profile, profile,
+ BFD_PROFILE_NAME_LEN);
+ else
+ (*bfd_info)->profile[0] = '\0';
}
if (!defaults)
@@ -121,6 +128,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx,
/*
* bfd_peer_sendmsg - Format and send a peer register/Unregister
* command to Zebra to be forwarded to BFD
+ *
+ * DEPRECATED: use zclient_bfd_command instead
*/
void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip, char *if_name,
@@ -143,8 +152,7 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
if (!zclient || zclient->sock < 0) {
if (bfd_debug)
zlog_debug(
- "%s: Can't send BFD peer register, Zebra client not "
- "established",
+ "%s: Can't send BFD peer register, Zebra client not established",
__func__);
return;
}
@@ -162,6 +170,11 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
args.min_rx = bfd_info->required_min_rx;
args.min_tx = bfd_info->desired_min_tx;
args.detection_multiplier = bfd_info->detect_mult;
+ if (bfd_info->profile[0]) {
+ args.profilelen = strlen(bfd_info->profile);
+ strlcpy(args.profile, bfd_info->profile,
+ sizeof(args.profile));
+ }
}
addrlen = family == AF_INET ? sizeof(struct in_addr)
@@ -217,8 +230,7 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
if (ifp == NULL) {
if (bfd_debug)
zlog_debug(
- "zebra_interface_bfd_read: "
- "Can't find interface by ifindex: %d ",
+ "zebra_interface_bfd_read: Can't find interface by ifindex: %d ",
ifindex);
return NULL;
}
@@ -320,8 +332,7 @@ void bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag,
json_bfd);
} else {
vty_out(vty,
- " %s%sDetect Multiplier: %d, Min Rx interval: %d,"
- " Min Tx interval: %d\n",
+ " %s%sDetect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
(extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ",
bfd_info->detect_mult, bfd_info->required_min_rx,
bfd_info->desired_min_tx);
@@ -397,8 +408,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
if (!zclient || zclient->sock < 0) {
if (bfd_debug)
zlog_debug(
- "%s: Can't send BFD client register, Zebra client not "
- "established",
+ "%s: Can't send BFD client register, Zebra client not established",
__func__);
return;
}
@@ -429,6 +439,15 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
struct stream *s;
size_t addrlen;
+ /* Individual reg/dereg messages are suppressed during shutdown. */
+ if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
+ if (bfd_debug)
+ zlog_debug(
+ "%s: Suppressing BFD peer reg/dereg messages",
+ __func__);
+ return -1;
+ }
+
/* Check socket. */
if (!zc || zc->sock < 0) {
if (bfd_debug)
diff --git a/lib/bfd.h b/lib/bfd.h
index d7d4b5fe35..ceab4628b6 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -92,8 +92,8 @@ extern int bfd_validate_param(struct vty *vty, const char *dm_str,
uint32_t *tx_val);
extern void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult, int defaults,
- int *command);
+ uint32_t min_tx, uint8_t detect_mult,
+ const char *profile, int defaults, int *command);
extern void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int family, void *dst_ip, void *src_ip,
char *if_name, int ttl, int multihop, int cbit,
diff --git a/lib/bitfield.h b/lib/bitfield.h
index 72980165f9..244938933b 100644
--- a/lib/bitfield.h
+++ b/lib/bitfield.h
@@ -58,7 +58,7 @@ typedef unsigned int word_t;
* @n: The current word number that is being used.
* @m: total number of words in 'data'
*/
-#define bitfield_t struct { word_t *data; size_t n, m; }
+typedef struct {word_t *data; size_t n, m; } bitfield_t;
/**
* Initialize the bits.
@@ -97,6 +97,16 @@ typedef unsigned int word_t;
#define bf_release_index(v, id) \
(v).data[bf_index(id)] &= ~(1 << (bf_offset(id)))
+/* check if an id is in use */
+#define bf_test_index(v, id) \
+ ((v).data[bf_index(id)] & (1 << (bf_offset(id))))
+
+/* check if the bit field has been setup */
+#define bf_is_inited(v) ((v).data)
+
+/* compare two bitmaps of the same length */
+#define bf_cmp(v1, v2) (memcmp((v1).data, (v2).data, ((v1).m * sizeof(word_t))))
+
/*
* return 0th index back to bitfield
*/
@@ -146,6 +156,37 @@ typedef unsigned int word_t;
(b) += (w * WORD_SIZE); \
} while (0)
+static inline unsigned int bf_find_next_set_bit(bitfield_t v,
+ word_t start_index)
+{
+ int start_bit;
+ unsigned long i, offset;
+
+ start_bit = start_index & (WORD_SIZE - 1);
+
+ for (i = bf_index(start_index); i < v.m; ++i) {
+ if (v.data[i] == 0) {
+ /* if the whole word is empty move to the next */
+ start_bit = 0;
+ continue;
+ }
+ /* scan one word for set bits */
+ for (offset = start_bit; offset < WORD_SIZE; ++offset) {
+ if ((v.data[i] >> offset) & 1)
+ return ((i * WORD_SIZE) + offset);
+ }
+ /* move to the next word */
+ start_bit = 0;
+ }
+ return WORD_MAX;
+}
+
+/* iterate through all the set bits */
+#define bf_for_each_set_bit(v, b, max) \
+ for ((b) = bf_find_next_set_bit((v), 0); \
+ (b) < max; \
+ (b) = bf_find_next_set_bit((v), (b) + 1))
+
/*
* Free the allocated memory for data
* @v: an instance of bitfield_t struct.
diff --git a/lib/buffer.c b/lib/buffer.c
index ff49bc83df..459d98e75d 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -327,8 +327,7 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width,
/* This should absolutely never occur. */
flog_err_sys(
EC_LIB_SYSTEM_CALL,
- "%s: corruption detected: iov_small overflowed; "
- "head %p, tail %p, head->next %p",
+ "%s: corruption detected: iov_small overflowed; head %p, tail %p, head->next %p",
__func__, (void *)b->head,
(void *)b->tail, (void *)b->head->next);
iov = XMALLOC(MTYPE_TMP,
diff --git a/lib/command.c b/lib/command.c
index fc43cce189..159ed07b38 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -841,9 +841,6 @@ enum node_type node_parent(enum node_type node)
case BFD_PROFILE_NODE:
ret = BFD_NODE;
break;
- case RPKI_VRF_NODE:
- ret = VRF_NODE;
- break;
default:
ret = CONFIG_NODE;
break;
@@ -907,6 +904,13 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
> vty->candidate_config->version)
nb_config_replace(vty->candidate_config,
running_config, true);
+
+ /*
+ * Perform pending commit (if any) before executing
+ * non-YANG command.
+ */
+ if (matched_element->attr != CMD_ATTR_YANG)
+ nb_cli_pending_commit_check(vty);
}
ret = matched_element->func(matched_element, vty, argc, argv);
diff --git a/lib/command.h b/lib/command.h
index 9e0fc783c7..e20bfe3318 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -159,7 +159,6 @@ enum node_type {
OPENFABRIC_NODE, /* OpenFabric router configuration node */
VRRP_NODE, /* VRRP node */
BMP_NODE, /* BMP config under router bgp */
- RPKI_VRF_NODE, /* RPKI node for VRF */
NODE_TYPE_MAX, /* maximum */
};
@@ -258,6 +257,12 @@ struct cmd_node {
#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
+#define DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
+
+#define DEFPY_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY_YANG(funcname, cmdname, cmdstr, helpstr)
+
#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
@@ -271,10 +276,16 @@ struct cmd_node {
#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
+#define DEFUN_YANG(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
+
/* DEFUN_NOSH for commands that vtysh should ignore */
#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
DEFUN(funcname, cmdname, cmdstr, helpstr)
+#define DEFUN_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_YANG(funcname, cmdname, cmdstr, helpstr)
+
/* DEFSH for vtysh. */
#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon)
@@ -283,6 +294,9 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \
daemon)
+#define DEFSH_YANG(daemon, cmdname, cmdstr, helpstr) \
+ DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, daemon)
+
/* DEFUN + DEFSH */
#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_FUNC_DECL(funcname) \
@@ -303,6 +317,9 @@ struct cmd_node {
DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, \
CMD_ATTR_DEPRECATED)
+#define DEFUNSH_YANG(daemon, funcname, cmdname, cmdstr, helpstr) \
+ DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
+
/* ALIAS macro which define existing command's alias. */
#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
@@ -318,6 +335,9 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \
CMD_ATTR_DEPRECATED, 0)
+#define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, 0)
+
#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
@@ -329,18 +349,6 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \
CMD_ATTR_DEPRECATED, daemon)
-#else /* VTYSH_EXTRACT_PL */
-#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
- DEFUN(funcname, cmdname, cmdstr, helpstr)
-
-#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr)
-
-#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
- DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr)
-
-#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr)
#endif /* VTYSH_EXTRACT_PL */
/* Some macroes */
@@ -359,6 +367,8 @@ struct cmd_node {
#define SHOW_STR "Show running system information\n"
#define IP_STR "IP information\n"
#define IPV6_STR "IPv6 information\n"
+#define SRTE_STR "SR-TE information\n"
+#define SRTE_COLOR_STR "SR-TE Color information\n"
#define NO_STR "Negate a command or set its defaults\n"
#define REDIST_STR "Redistribute information from another routing protocol\n"
#define CLEAR_STR "Reset functions\n"
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 1efe8b1803..179e104a57 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -74,6 +74,7 @@ enum cmd_token_type {
enum { CMD_ATTR_NORMAL,
CMD_ATTR_DEPRECATED,
CMD_ATTR_HIDDEN,
+ CMD_ATTR_YANG,
};
/* Comamand token struct. */
diff --git a/lib/defun_lex.l b/lib/defun_lex.l
index 19b06f51b8..bc5fbd24d9 100644
--- a/lib/defun_lex.l
+++ b/lib/defun_lex.l
@@ -140,6 +140,8 @@ SPECIAL [(),]
"DEFPY_NOSH" value = strdup(yytext); return DEFUNNY;
"DEFPY_ATTR" value = strdup(yytext); return DEFUNNY;
"DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY;
+"DEFPY_YANG" value = strdup(yytext); return DEFUNNY;
+"DEFPY_YANG_NOSH" value = strdup(yytext); return DEFUNNY;
"ALIAS" value = strdup(yytext); return DEFUNNY;
"ALIAS_HIDDEN" value = strdup(yytext); return DEFUNNY;
"install_element" value = strdup(yytext); return INSTALL;
diff --git a/lib/ferr.c b/lib/ferr.c
index ccf63dea17..7b923da177 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -130,7 +130,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
if (json) {
char key[11];
- snprintf(key, sizeof(key), "%"PRIu32, ref->code);
+ snprintf(key, sizeof(key), "%u", ref->code);
obj = json_object_new_object();
json_object_string_add(obj, "title", ref->title);
json_object_string_add(obj, "description",
@@ -142,7 +142,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
char pbuf[256];
char ubuf[256];
- snprintf(pbuf, sizeof(pbuf), "\nError %"PRIu32" - %s",
+ snprintf(pbuf, sizeof(pbuf), "\nError %u - %s",
ref->code, ref->title);
memset(ubuf, '=', strlen(pbuf));
ubuf[strlen(pbuf)] = '\0';
diff --git a/lib/filter.h b/lib/filter.h
index 76e992bf8e..d41f3b65cd 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -170,11 +170,6 @@ enum yang_prefix_list_action {
struct lyd_node;
struct vty;
-extern void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void access_list_legacy_remark_show(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
extern void access_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index fe8190d098..8c7a515dc5 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -169,7 +169,7 @@ static long acl_get_seq(struct vty *vty, const char *xpath)
/*
* Cisco (legacy) access lists.
*/
-DEFPY(
+DEFPY_YANG(
access_list_std, access_list_std_cmd,
"access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
ACCESS_LIST_STR
@@ -193,7 +193,8 @@ DEFPY(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
+ number_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -213,13 +214,13 @@ DEFPY(
concat_addr_mask_v4(host_str, mask_str, ipmask, sizeof(ipmask));
nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask);
} else {
- nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_access_list_std, no_access_list_std_cmd,
"no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
NO_STR
@@ -244,7 +245,7 @@ DEFPY(
if (seq_str != NULL) {
snprintf(
xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
number_str, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -252,7 +253,8 @@ DEFPY(
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
+ number_str);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -278,7 +280,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
access_list_ext, access_list_ext_cmd,
"access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
ACCESS_LIST_STR
@@ -308,7 +310,8 @@ DEFPY(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
+ number_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -329,7 +332,7 @@ DEFPY(
sizeof(ipmask));
nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask);
} else {
- nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
}
if (dst_str != NULL && dst_mask_str == NULL) {
@@ -348,7 +351,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_access_list_ext, no_access_list_ext_cmd,
"no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
NO_STR
@@ -379,7 +382,7 @@ DEFPY(
if (seq_str != NULL) {
snprintfrr(
xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
number_str, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -387,7 +390,8 @@ DEFPY(
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
+ number_str);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -429,131 +433,10 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
- no_access_list_legacy, no_access_list_legacy_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number",
- NO_STR
- ACCESS_LIST_STR
- ACCESS_LIST_XLEG_STR)
-{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
-}
-
-void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults)
-{
- uint16_t number = yang_dnode_get_uint16(dnode, "../number");
- bool extended;
- struct prefix p;
- struct in_addr mask;
-
- vty_out(vty, "access-list %d seq %s %s", number,
- yang_dnode_get_string(dnode, "./sequence"),
- yang_dnode_get_string(dnode, "./action"));
-
- extended = (number >= 100 && number <= 199)
- || (number >= 2000 && number <= 2699);
- if (extended)
- vty_out(vty, " ip");
-
- if (yang_dnode_exists(dnode, "./network")) {
- yang_dnode_get_prefix(&p, dnode, "./network");
- masklen2ip(p.prefixlen, &mask);
- vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
- } else if (yang_dnode_exists(dnode, "./host")) {
- if (extended)
- vty_out(vty, " host");
-
- vty_out(vty, " %s", yang_dnode_get_string(dnode, "./host"));
- } else if (yang_dnode_exists(dnode, "./any"))
- vty_out(vty, " any");
-
- if (extended) {
- if (yang_dnode_exists(dnode, "./destination-network")) {
- yang_dnode_get_prefix(&p, dnode,
- "./destination-network");
- masklen2ip(p.prefixlen, &mask);
- vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
- } else if (yang_dnode_exists(dnode, "./destination-host"))
- vty_out(vty, " host %s",
- yang_dnode_get_string(dnode,
- "./destination-host"));
- else if (yang_dnode_exists(dnode, "./destination-any"))
- vty_out(vty, " any");
- }
-
- vty_out(vty, "\n");
-}
-
-DEFPY(
- access_list_legacy_remark, access_list_legacy_remark_cmd,
- "access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
- ACCESS_LIST_STR
- ACCESS_LIST_XLEG_STR
- ACCESS_LIST_REMARK_STR
- ACCESS_LIST_REMARK_LINE_STR)
-{
- int rv;
- char *remark;
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
- remark = argv_concat(argv, argc, 3);
- nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
- rv = nb_cli_apply_changes(vty, xpath);
- XFREE(MTYPE_TMP, remark);
-
- return rv;
-}
-
-DEFPY(
- no_access_list_legacy_remark, no_access_list_legacy_remark_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark",
- NO_STR
- ACCESS_LIST_STR
- ACCESS_LIST_XLEG_STR
- ACCESS_LIST_REMARK_STR)
-{
- char xpath[XPATH_MAXLEN];
-
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list-legacy[number='%s']/remark",
- number_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
-}
-
-ALIAS(
- no_access_list_legacy_remark, no_access_list_legacy_remark_line_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
- NO_STR
- ACCESS_LIST_STR
- ACCESS_LIST_XLEG_STR
- ACCESS_LIST_REMARK_STR
- ACCESS_LIST_REMARK_LINE_STR)
-
-void access_list_legacy_remark_show(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults)
-{
- vty_out(vty, "access-list %s remark %s\n",
- yang_dnode_get_string(dnode, "../number"),
- yang_dnode_get_string(dnode, NULL));
-}
-
/*
* Zebra access lists.
*/
-DEFPY(
+DEFPY_YANG(
access_list, access_list_cmd,
"access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
ACCESS_LIST_STR
@@ -599,7 +482,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_access_list, no_access_list_cmd,
"no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
NO_STR
@@ -656,7 +539,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_access_list_all, no_access_list_all_cmd,
"no access-list WORD$name",
NO_STR
@@ -672,7 +555,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
access_list_remark, access_list_remark_cmd,
"access-list WORD$name remark LINE...",
ACCESS_LIST_STR
@@ -696,7 +579,7 @@ DEFPY(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_access_list_remark, no_access_list_remark_cmd,
"no access-list WORD$name remark",
NO_STR
@@ -723,7 +606,7 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
-DEFPY(
+DEFPY_YANG(
ipv6_access_list, ipv6_access_list_cmd,
"ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
IPV6_STR
@@ -770,7 +653,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_access_list, no_ipv6_access_list_cmd,
"no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
NO_STR
@@ -828,7 +711,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_access_list_all, no_ipv6_access_list_all_cmd,
"no ipv6 access-list WORD$name",
NO_STR
@@ -845,7 +728,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
ipv6_access_list_remark, ipv6_access_list_remark_cmd,
"ipv6 access-list WORD$name remark LINE...",
IPV6_STR
@@ -870,7 +753,7 @@ DEFPY(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd,
"no ipv6 access-list WORD$name remark",
NO_STR
@@ -899,7 +782,7 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
-DEFPY(
+DEFPY_YANG(
mac_access_list, mac_access_list_cmd,
"mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
MAC_STR
@@ -942,7 +825,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_mac_access_list, no_mac_access_list_cmd,
"no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>",
NO_STR
@@ -999,7 +882,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_mac_access_list_all, no_mac_access_list_all_cmd,
"no mac access-list WORD$name",
NO_STR
@@ -1016,7 +899,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
mac_access_list_remark, mac_access_list_remark_cmd,
"mac access-list WORD$name remark LINE...",
MAC_STR
@@ -1041,7 +924,7 @@ DEFPY(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_mac_access_list_remark, no_mac_access_list_remark_cmd,
"no mac access-list WORD$name remark",
NO_STR
@@ -1077,6 +960,9 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode,
struct prefix p;
bool is_any;
bool is_exact = false;
+ bool cisco_style = false;
+ bool cisco_extended = false;
+ struct in_addr mask;
char macstr[PREFIX2STR_BUFFER];
is_any = yang_dnode_exists(dnode, "./any");
@@ -1085,8 +971,19 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode,
if (is_any)
break;
- yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
- is_exact = yang_dnode_get_bool(dnode, "./ipv4-exact-match");
+ if (yang_dnode_exists(dnode, "./host")
+ || yang_dnode_exists(dnode, "./network")
+ || yang_dnode_exists(dnode, "./source-any")) {
+ cisco_style = true;
+ if (yang_dnode_exists(dnode, "./destination-host")
+ || yang_dnode_exists(dnode, "./destination-network")
+ || yang_dnode_exists(dnode, "./destination-any"))
+ cisco_extended = true;
+ } else {
+ yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
+ is_exact = yang_dnode_get_bool(dnode,
+ "./ipv4-exact-match");
+ }
break;
case YALT_IPV6: /* ipv6 */
vty_out(vty, "ipv6 ");
@@ -1110,6 +1007,48 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_string(dnode, "./sequence"),
yang_dnode_get_string(dnode, "./action"));
+ /* Handle Cisco style access lists. */
+ if (cisco_style) {
+ if (cisco_extended)
+ vty_out(vty, " ip");
+
+ if (yang_dnode_exists(dnode, "./network")) {
+ yang_dnode_get_prefix(&p, dnode, "./network");
+ masklen2ip(p.prefixlen, &mask);
+ vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
+ } else if (yang_dnode_exists(dnode, "./host")) {
+ if (cisco_extended)
+ vty_out(vty, " host");
+
+ vty_out(vty, " %s",
+ yang_dnode_get_string(dnode, "./host"));
+ } else if (yang_dnode_exists(dnode, "./source-any"))
+ vty_out(vty, " any");
+
+ /* Not extended, exit earlier. */
+ if (!cisco_extended) {
+ vty_out(vty, "\n");
+ return;
+ }
+
+ /* Handle destination address. */
+ if (yang_dnode_exists(dnode, "./destination-network")) {
+ yang_dnode_get_prefix(&p, dnode,
+ "./destination-network");
+ masklen2ip(p.prefixlen, &mask);
+ vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
+ } else if (yang_dnode_exists(dnode, "./destination-host"))
+ vty_out(vty, " host %s",
+ yang_dnode_get_string(dnode,
+ "./destination-host"));
+ else if (yang_dnode_exists(dnode, "./destination-any"))
+ vty_out(vty, " any");
+
+ vty_out(vty, "\n");
+ return;
+ }
+
+ /* Zebra style access list. */
if (!is_any) {
/* If type is MAC don't show '/mask'. */
if (type == 2 /* mac */) {
@@ -1243,7 +1182,7 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name,
return rv;
}
-DEFPY(
+DEFPY_YANG(
ip_prefix_list, ip_prefix_list_cmd,
"ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>",
IP_STR
@@ -1300,7 +1239,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_ip_prefix_list, no_ip_prefix_list_cmd,
"no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>",
NO_STR
@@ -1320,7 +1259,7 @@ DEFPY(
(struct prefix *)prefix, ge, le);
}
-DEFPY(
+DEFPY_YANG(
no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
"no ip prefix-list WORD$name seq (1-4294967295)$seq",
NO_STR
@@ -1332,7 +1271,7 @@ DEFPY(
return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0);
}
-DEFPY(
+DEFPY_YANG(
no_ip_prefix_list_all, no_ip_prefix_list_all_cmd,
"no ip prefix-list WORD$name",
NO_STR
@@ -1349,7 +1288,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
ip_prefix_list_remark, ip_prefix_list_remark_cmd,
"ip prefix-list WORD$name description LINE...",
IP_STR
@@ -1374,7 +1313,7 @@ DEFPY(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd,
"no ip prefix-list WORD$name description",
NO_STR
@@ -1403,7 +1342,7 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
-DEFPY(
+DEFPY_YANG(
ipv6_prefix_list, ipv6_prefix_list_cmd,
"ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
IPV6_STR
@@ -1460,7 +1399,7 @@ DEFPY(
return nb_cli_apply_changes(vty, xpath_entry);
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_prefix_list, no_ipv6_prefix_list_cmd,
"no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
NO_STR
@@ -1480,7 +1419,7 @@ DEFPY(
(struct prefix *)prefix, ge, le);
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd,
"no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
NO_STR
@@ -1492,7 +1431,7 @@ DEFPY(
return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0);
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd,
"no ipv6 prefix-list WORD$name",
NO_STR
@@ -1509,7 +1448,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd,
"ipv6 prefix-list WORD$name description LINE...",
IPV6_STR
@@ -1534,7 +1473,7 @@ DEFPY(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd,
"no ipv6 prefix-list WORD$name description",
NO_STR
@@ -1648,10 +1587,6 @@ void filter_cli_init(void)
install_element(CONFIG_NODE, &no_access_list_std_cmd);
install_element(CONFIG_NODE, &access_list_ext_cmd);
install_element(CONFIG_NODE, &no_access_list_ext_cmd);
- install_element(CONFIG_NODE, &no_access_list_legacy_cmd);
- install_element(CONFIG_NODE, &access_list_legacy_remark_cmd);
- install_element(CONFIG_NODE, &no_access_list_legacy_remark_cmd);
- install_element(CONFIG_NODE, &no_access_list_legacy_remark_line_cmd);
/* access-list zebra-style. */
install_element(CONFIG_NODE, &access_list_cmd);
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index 83cf586ed3..91691d2f1d 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -24,6 +24,7 @@
#include "lib/northbound.h"
#include "lib/prefix.h"
+#include "lib/printfrr.h"
#include "lib/filter.h"
#include "lib/plist.h"
@@ -39,20 +40,19 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen)
return hostaddr & mask.s_addr;
}
-static enum nb_error
-prefix_list_length_validate(const struct lyd_node *dnode)
+static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
{
- int type = yang_dnode_get_enum(dnode, "../../type");
+ int type = yang_dnode_get_enum(args->dnode, "../../type");
const char *xpath_le = NULL, *xpath_ge = NULL;
struct prefix p;
uint8_t le, ge;
if (type == YPLT_IPV4) {
- yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix");
+ yang_dnode_get_prefix(&p, args->dnode, "../ipv4-prefix");
xpath_le = "../ipv4-prefix-length-lesser-or-equal";
xpath_ge = "../ipv4-prefix-length-greater-or-equal";
} else {
- yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix");
+ yang_dnode_get_prefix(&p, args->dnode, "../ipv6-prefix");
xpath_le = "../ipv6-prefix-length-lesser-or-equal";
xpath_ge = "../ipv6-prefix-length-greater-or-equal";
}
@@ -61,19 +61,18 @@ prefix_list_length_validate(const struct lyd_node *dnode)
* Check rule:
* prefix length <= le.
*/
- if (yang_dnode_exists(dnode, xpath_le)) {
- le = yang_dnode_get_uint8(dnode, xpath_le);
+ if (yang_dnode_exists(args->dnode, xpath_le)) {
+ le = yang_dnode_get_uint8(args->dnode, xpath_le);
if (p.prefixlen > le)
goto log_and_fail;
-
}
/*
* Check rule:
* prefix length < ge.
*/
- if (yang_dnode_exists(dnode, xpath_ge)) {
- ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (yang_dnode_exists(args->dnode, xpath_ge)) {
+ ge = yang_dnode_get_uint8(args->dnode, xpath_ge);
if (p.prefixlen >= ge)
goto log_and_fail;
}
@@ -82,19 +81,21 @@ prefix_list_length_validate(const struct lyd_node *dnode)
* Check rule:
* ge <= le.
*/
- if (yang_dnode_exists(dnode, xpath_le) &&
- yang_dnode_exists(dnode, xpath_ge)) {
- le = yang_dnode_get_uint8(dnode, xpath_le);
- ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (yang_dnode_exists(args->dnode, xpath_le)
+ && yang_dnode_exists(args->dnode, xpath_ge)) {
+ le = yang_dnode_get_uint8(args->dnode, xpath_le);
+ ge = yang_dnode_get_uint8(args->dnode, xpath_ge);
if (ge > le)
goto log_and_fail;
}
return NB_OK;
- log_and_fail:
- zlog_info("prefix-list: invalid prefix range for %pFX: "
- "Make sure that mask length < ge <= le", &p);
+log_and_fail:
+ snprintfrr(
+ args->errmsg, args->errmsg_len,
+ "Invalid prefix range for %pFX: Make sure that mask length < ge <= le",
+ &p);
return NB_ERR_VALIDATION;
}
@@ -112,24 +113,38 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
}
/*
- * XPath: /frr-filter:lib/access-list-legacy
+ * XPath: /frr-filter:lib/access-list
*/
-static int lib_access_list_legacy_create(struct nb_cb_create_args *args)
+static int lib_access_list_create(struct nb_cb_create_args *args)
{
- struct access_list *acl;
+ struct access_list *acl = NULL;
const char *acl_name;
+ int type;
if (args->event != NB_EV_APPLY)
return NB_OK;
- acl_name = yang_dnode_get_string(args->dnode, "./number");
- acl = access_list_get(AFI_IP, acl_name);
+ type = yang_dnode_get_enum(args->dnode, "./type");
+ acl_name = yang_dnode_get_string(args->dnode, "./name");
+
+ switch (type) {
+ case YALT_IPV4:
+ acl = access_list_get(AFI_IP, acl_name);
+ break;
+ case YALT_IPV6:
+ acl = access_list_get(AFI_IP6, acl_name);
+ break;
+ case YALT_MAC:
+ acl = access_list_get(AFI_L2VPN, acl_name);
+ break;
+ }
+
nb_running_set_entry(args->dnode, acl);
return NB_OK;
}
-static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args)
+static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
{
struct access_master *am;
struct access_list *acl;
@@ -148,9 +163,9 @@ static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args)
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/remark
+ * XPath: /frr-filter:lib/access-list/remark
*/
-static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args)
+static int lib_access_list_remark_modify(struct nb_cb_modify_args *args)
{
struct access_list *acl;
const char *remark;
@@ -169,7 +184,7 @@ static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args)
}
static int
-lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args)
+lib_access_list_remark_destroy(struct nb_cb_destroy_args *args)
{
struct access_list *acl;
@@ -183,31 +198,20 @@ lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
}
+
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry
+ * XPath: /frr-filter:lib/access-list/entry
*/
-static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args)
+static int lib_access_list_entry_create(struct nb_cb_create_args *args)
{
- struct filter_cisco *fc;
struct access_list *acl;
struct filter *f;
- uint32_t aclno;
-
- /* TODO: validate `filter_lookup_cisco` returns NULL. */
if (args->event != NB_EV_APPLY)
return NB_OK;
- aclno = yang_dnode_get_uint16(args->dnode, "../number");
-
f = filter_new();
- f->cisco = 1;
f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
- fc = &f->u.cfilter;
- if ((aclno >= 1 && aclno <= 99) || (aclno >= 1300 && aclno <= 1999))
- fc->extended = 0;
- else
- fc->extended = 1;
acl = nb_running_get_entry(args->dnode, NULL, true);
f->acl = acl;
@@ -217,7 +221,7 @@ static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args)
return NB_OK;
}
-static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args)
+static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
{
struct access_list *acl;
struct filter *f;
@@ -233,10 +237,10 @@ static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args)
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/action
+ * XPath: /frr-filter:lib/access-list/entry/action
*/
static int
-lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args)
+lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
{
const char *filter_type;
struct filter *f;
@@ -255,86 +259,81 @@ lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args)
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/host
+ * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
*/
static int
-lib_access_list_legacy_entry_host_modify(struct nb_cb_modify_args *args)
+lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
{
- struct filter_cisco *fc;
+ struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fc = &f->u.cfilter;
- yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
- fc->addr_mask.s_addr = INADDR_ANY;
+ f->cisco = 0;
+ fz = &f->u.zfilter;
+ yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
return NB_OK;
}
static int
-lib_access_list_legacy_entry_host_destroy(struct nb_cb_destroy_args *args)
+lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
{
- struct filter_cisco *fc;
+ struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ fz = &f->u.zfilter;
+ memset(&fz->prefix, 0, sizeof(fz->prefix));
return NB_OK;
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/network
+ * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
*/
static int
-lib_access_list_legacy_entry_network_modify(struct nb_cb_modify_args *args)
+lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
{
- struct filter_cisco *fc;
+ struct filter_zebra *fz;
struct filter *f;
- struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fc = &f->u.cfilter;
- yang_dnode_get_prefix(&p, args->dnode, NULL);
- fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
- masklen2ip(p.prefixlen, &fc->addr_mask);
+ fz = &f->u.zfilter;
+ fz->exact = yang_dnode_get_bool(args->dnode, NULL);
return NB_OK;
}
static int
-lib_access_list_legacy_entry_network_destroy(struct nb_cb_destroy_args *args)
+lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
{
- struct filter_cisco *fc;
+ struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ fz = &f->u.zfilter;
+ fz->exact = 0;
return NB_OK;
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/any
+ * XPath: /frr-filter:lib/access-list/entry/host
*/
static int
-lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args)
+lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
@@ -343,15 +342,16 @@ lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
+ f->cisco = 1;
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
+ fc->addr_mask.s_addr = INADDR_ANY;
return NB_OK;
}
static int
-lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args)
+lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
@@ -368,27 +368,30 @@ lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args)
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/destination-host
+ * XPath: /frr-filter:lib/access-list/entry/network
*/
-static int lib_access_list_legacy_entry_destination_host_modify(
- struct nb_cb_modify_args *args)
+static int
+lib_access_list_entry_network_modify(struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
+ struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
+ f->cisco = 1;
fc = &f->u.cfilter;
- yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
- fc->mask_mask.s_addr = INADDR_ANY;
+ yang_dnode_get_prefix(&p, args->dnode, NULL);
+ fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
+ masklen2ip(p.prefixlen, &fc->addr_mask);
return NB_OK;
}
-static int lib_access_list_legacy_entry_destination_host_destroy(
- struct nb_cb_destroy_args *args)
+static int
+lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
@@ -398,36 +401,35 @@ static int lib_access_list_legacy_entry_destination_host_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/destination-network
+ * XPath: /frr-filter:lib/access-list/entry/source-any
*/
-static int lib_access_list_legacy_entry_destination_network_modify(
- struct nb_cb_modify_args *args)
+static int
+lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
{
struct filter_cisco *fc;
struct filter *f;
- struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
+ f->cisco = 1;
fc = &f->u.cfilter;
- yang_dnode_get_prefix(&p, args->dnode, NULL);
- fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
- masklen2ip(p.prefixlen, &fc->mask_mask);
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
-static int lib_access_list_legacy_entry_destination_network_destroy(
- struct nb_cb_destroy_args *args)
+static int
+lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
@@ -437,17 +439,17 @@ static int lib_access_list_legacy_entry_destination_network_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
- * XPath: /frr-filter:lib/access-list-legacy/entry/destination-any
+ * XPath: /frr-filter:lib/access-list/entry/destination-host
*/
-static int lib_access_list_legacy_entry_destination_any_create(
- struct nb_cb_create_args *args)
+static int lib_access_list_entry_destination_host_modify(
+ struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
@@ -457,13 +459,14 @@ static int lib_access_list_legacy_entry_destination_any_create(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ fc->extended = 1;
+ yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
+ fc->mask_mask.s_addr = INADDR_ANY;
return NB_OK;
}
-static int lib_access_list_legacy_entry_destination_any_destroy(
+static int lib_access_list_entry_destination_host_destroy(
struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
@@ -474,6 +477,7 @@ static int lib_access_list_legacy_entry_destination_any_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
+ fc->extended = 0;
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = INADDR_NONE;
@@ -481,160 +485,81 @@ static int lib_access_list_legacy_entry_destination_any_destroy(
}
/*
- * XPath: /frr-filter:lib/access-list
+ * XPath: /frr-filter:lib/access-list/entry/destination-network
*/
-static int lib_access_list_create(struct nb_cb_create_args *args)
-{
- struct access_list *acl = NULL;
- const char *acl_name;
- int type;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- type = yang_dnode_get_enum(args->dnode, "./type");
- acl_name = yang_dnode_get_string(args->dnode, "./name");
-
- switch (type) {
- case YALT_IPV4:
- acl = access_list_get(AFI_IP, acl_name);
- break;
- case YALT_IPV6:
- acl = access_list_get(AFI_IP6, acl_name);
- break;
- case YALT_MAC:
- acl = access_list_get(AFI_L2VPN, acl_name);
- break;
- }
-
- nb_running_set_entry(args->dnode, acl);
-
- return NB_OK;
-}
-
-static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
-{
- struct access_master *am;
- struct access_list *acl;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- acl = nb_running_unset_entry(args->dnode);
- am = acl->master;
- if (am->delete_hook)
- am->delete_hook(acl);
-
- access_list_delete(acl);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-filter:lib/access-list/entry
- */
-static int lib_access_list_entry_create(struct nb_cb_create_args *args)
-{
- struct access_list *acl;
- struct filter *f;
-
- /* TODO: validate `filter_lookup_zebra` returns NULL. */
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- f = filter_new();
- f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
-
- acl = nb_running_get_entry(args->dnode, NULL, true);
- f->acl = acl;
- access_list_filter_add(acl, f);
- nb_running_set_entry(args->dnode, f);
-
- return NB_OK;
-}
-
-static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
-{
- struct access_list *acl;
- struct filter *f;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- f = nb_running_unset_entry(args->dnode);
- acl = f->acl;
- access_list_filter_delete(acl, f);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
- */
-static int
-lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+static int lib_access_list_entry_destination_network_modify(
+ struct nb_cb_modify_args *args)
{
- struct filter_zebra *fz;
+ struct filter_cisco *fc;
struct filter *f;
+ struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fz = &f->u.zfilter;
- yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
+ fc = &f->u.cfilter;
+ fc->extended = 1;
+ yang_dnode_get_prefix(&p, args->dnode, NULL);
+ fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
+ masklen2ip(p.prefixlen, &fc->mask_mask);
return NB_OK;
}
-static int
-lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+static int lib_access_list_entry_destination_network_destroy(
+ struct nb_cb_destroy_args *args)
{
- struct filter_zebra *fz;
+ struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fz = &f->u.zfilter;
- memset(&fz->prefix, 0, sizeof(fz->prefix));
+ fc = &f->u.cfilter;
+ fc->extended = 0;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
- * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
+ * XPath: /frr-filter:lib/access-list/entry/destination-any
*/
-static int
-lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
+static int lib_access_list_entry_destination_any_create(
+ struct nb_cb_create_args *args)
{
- struct filter_zebra *fz;
+ struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fz = &f->u.zfilter;
- fz->exact = yang_dnode_get_bool(args->dnode, NULL);
+ fc = &f->u.cfilter;
+ fc->extended = 1;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
-static int
-lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
+static int lib_access_list_entry_destination_any_destroy(
+ struct nb_cb_destroy_args *args)
{
- struct filter_zebra *fz;
+ struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
- fz = &f->u.zfilter;
- fz->exact = 0;
+ fc = &f->u.cfilter;
+ fc->extended = 0;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
@@ -652,6 +577,7 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
+ f->cisco = 0;
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
@@ -905,7 +831,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args->dnode) != NB_OK)
+ prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
@@ -954,7 +880,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args->dnode) != NB_OK)
+ prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
@@ -1060,117 +986,88 @@ const struct frr_yang_module_info frr_filter_info = {
.name = "frr-filter",
.nodes = {
{
- .xpath = "/frr-filter:lib/access-list-legacy",
- .cbs = {
- .create = lib_access_list_legacy_create,
- .destroy = lib_access_list_legacy_destroy,
- }
- },
- {
- .xpath = "/frr-filter:lib/access-list-legacy/remark",
- .cbs = {
- .modify = lib_access_list_legacy_remark_modify,
- .destroy = lib_access_list_legacy_remark_destroy,
- .cli_show = access_list_legacy_remark_show,
- }
- },
- {
- .xpath = "/frr-filter:lib/access-list-legacy/entry",
- .cbs = {
- .create = lib_access_list_legacy_entry_create,
- .destroy = lib_access_list_legacy_entry_destroy,
- .cli_show = access_list_legacy_show,
- }
- },
- {
- .xpath = "/frr-filter:lib/access-list-legacy/entry/action",
- .cbs = {
- .modify = lib_access_list_legacy_entry_action_modify,
- }
- },
- {
- .xpath = "/frr-filter:lib/access-list-legacy/entry/host",
+ .xpath = "/frr-filter:lib/access-list",
.cbs = {
- .modify = lib_access_list_legacy_entry_host_modify,
- .destroy = lib_access_list_legacy_entry_host_destroy,
+ .create = lib_access_list_create,
+ .destroy = lib_access_list_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list-legacy/entry/network",
+ .xpath = "/frr-filter:lib/access-list/remark",
.cbs = {
- .modify = lib_access_list_legacy_entry_network_modify,
- .destroy = lib_access_list_legacy_entry_network_destroy,
+ .modify = lib_access_list_remark_modify,
+ .destroy = lib_access_list_remark_destroy,
+ .cli_show = access_list_remark_show,
}
},
{
- .xpath = "/frr-filter:lib/access-list-legacy/entry/any",
+ .xpath = "/frr-filter:lib/access-list/entry",
.cbs = {
- .create = lib_access_list_legacy_entry_any_create,
- .destroy = lib_access_list_legacy_entry_any_destroy,
+ .create = lib_access_list_entry_create,
+ .destroy = lib_access_list_entry_destroy,
+ .cli_show = access_list_show,
}
},
{
- .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-host",
+ .xpath = "/frr-filter:lib/access-list/entry/action",
.cbs = {
- .modify = lib_access_list_legacy_entry_destination_host_modify,
- .destroy = lib_access_list_legacy_entry_destination_host_destroy,
+ .modify = lib_access_list_entry_action_modify,
}
},
{
- .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-network",
+ .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
.cbs = {
- .modify = lib_access_list_legacy_entry_destination_network_modify,
- .destroy = lib_access_list_legacy_entry_destination_network_destroy,
+ .modify = lib_access_list_entry_ipv4_prefix_modify,
+ .destroy = lib_access_list_entry_ipv4_prefix_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-any",
+ .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
.cbs = {
- .create = lib_access_list_legacy_entry_destination_any_create,
- .destroy = lib_access_list_legacy_entry_destination_any_destroy,
+ .modify = lib_access_list_entry_ipv4_exact_match_modify,
+ .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list",
+ .xpath = "/frr-filter:lib/access-list/entry/host",
.cbs = {
- .create = lib_access_list_create,
- .destroy = lib_access_list_destroy,
+ .modify = lib_access_list_entry_host_modify,
+ .destroy = lib_access_list_entry_host_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list/remark",
+ .xpath = "/frr-filter:lib/access-list/entry/network",
.cbs = {
- .modify = lib_access_list_legacy_remark_modify,
- .destroy = lib_access_list_legacy_remark_destroy,
- .cli_show = access_list_remark_show,
+ .modify = lib_access_list_entry_network_modify,
+ .destroy = lib_access_list_entry_network_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list/entry",
+ .xpath = "/frr-filter:lib/access-list/entry/source-any",
.cbs = {
- .create = lib_access_list_entry_create,
- .destroy = lib_access_list_entry_destroy,
- .cli_show = access_list_show,
+ .create = lib_access_list_entry_source_any_create,
+ .destroy = lib_access_list_entry_source_any_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list/entry/action",
+ .xpath = "/frr-filter:lib/access-list/entry/destination-host",
.cbs = {
- .modify = lib_access_list_legacy_entry_action_modify,
+ .modify = lib_access_list_entry_destination_host_modify,
+ .destroy = lib_access_list_entry_destination_host_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
+ .xpath = "/frr-filter:lib/access-list/entry/destination-network",
.cbs = {
- .modify = lib_access_list_entry_ipv4_prefix_modify,
- .destroy = lib_access_list_entry_ipv4_prefix_destroy,
+ .modify = lib_access_list_entry_destination_network_modify,
+ .destroy = lib_access_list_entry_destination_network_destroy,
}
},
{
- .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
+ .xpath = "/frr-filter:lib/access-list/entry/destination-any",
.cbs = {
- .modify = lib_access_list_entry_ipv4_exact_match_modify,
- .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
+ .create = lib_access_list_entry_destination_any_create,
+ .destroy = lib_access_list_entry_destination_any_destroy,
}
},
{
diff --git a/lib/id_alloc.c b/lib/id_alloc.c
index 7c7f2c4689..95096fa5f0 100644
--- a/lib/id_alloc.c
+++ b/lib/id_alloc.c
@@ -108,7 +108,7 @@ static struct id_alloc_page *find_or_create_page(struct id_alloc *alloc,
} else if (page != NULL && create) {
flog_err(
EC_LIB_ID_CONSISTENCY,
- "ID Allocator %s attempt to re-create page at %" PRIu32,
+ "ID Allocator %s attempt to re-create page at %u",
alloc->name, id);
}
@@ -131,8 +131,7 @@ void idalloc_free(struct id_alloc *alloc, uint32_t id)
page = find_or_create_page(alloc, id, 0);
if (!page) {
flog_err(EC_LIB_ID_CONSISTENCY,
- "ID Allocator %s cannot free #%" PRIu32
- ". ID Block does not exist.",
+ "ID Allocator %s cannot free #%u. ID Block does not exist.",
alloc->name, id);
return;
}
@@ -142,8 +141,7 @@ void idalloc_free(struct id_alloc *alloc, uint32_t id)
if ((page->allocated_mask[word] & (1 << offset)) == 0) {
flog_err(EC_LIB_ID_CONSISTENCY,
- "ID Allocator %s cannot free #%" PRIu32
- ". ID was not allocated at the time of free.",
+ "ID Allocator %s cannot free #%u. ID was not allocated at the time of free.",
alloc->name, id);
return;
}
@@ -285,8 +283,7 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id)
if (page->allocated_mask[word] & (((uint32_t)1) << offset)) {
flog_err(EC_LIB_ID_CONSISTENCY,
- "ID Allocator %s could not reserve %" PRIu32
- " because it is already allocated.",
+ "ID Allocator %s could not reserve %u because it is already allocated.",
alloc->name, id);
return IDALLOC_INVALID;
}
diff --git a/lib/if.c b/lib/if.c
index e12b4f8c8f..d8392708e1 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -217,16 +217,14 @@ struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
return ifp;
}
-struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
- char *optional_name)
+struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
{
struct interface *ifp;
ifp = if_new(vrf_id);
if_set_index(ifp, ifindex);
- if (optional_name)
- if_set_name(ifp, optional_name);
+
hook_call(if_add, ifp);
return ifp;
}
@@ -573,8 +571,7 @@ 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,
- char *optional_name)
+struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
{
struct interface *ifp;
@@ -584,7 +581,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
ifp = if_lookup_by_ifindex(ifindex, vrf_id);
if (ifp)
return ifp;
- return if_create_ifindex(ifindex, vrf_id, optional_name);
+ return if_create_ifindex(ifindex, vrf_id);
case VRF_BACKEND_VRF_LITE:
ifp = if_lookup_by_index_all_vrf(ifindex);
if (ifp) {
@@ -596,7 +593,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
if_update_to_new_vrf(ifp, vrf_id);
return ifp;
}
- return if_create_ifindex(ifindex, vrf_id, optional_name);
+ return if_create_ifindex(ifindex, vrf_id);
}
return NULL;
@@ -785,8 +782,7 @@ static void if_dump(const struct interface *ifp)
struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
zlog_info(
- "Interface %s vrf %s(%u) index %d metric %d mtu %d "
- "mtu6 %d %s",
+ "Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s",
ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
ifp->metric, ifp->mtu, ifp->mtu6,
if_flag_dump(ifp->flags));
@@ -1322,7 +1318,7 @@ void if_link_params_free(struct interface *ifp)
/*
* XPath: /frr-interface:lib/interface
*/
-DEFPY_NOSH (interface,
+DEFPY_YANG_NOSH (interface,
interface_cmd,
"interface IFNAME [vrf NAME$vrf_name]",
"Select an interface to configure\n"
@@ -1385,6 +1381,7 @@ DEFPY_NOSH (interface,
* all interface-level commands are converted to the new
* northbound model.
*/
+ nb_cli_pending_commit_check(vty);
ifp = if_lookup_by_name(ifname, vrf_id);
if (ifp)
VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
@@ -1393,7 +1390,7 @@ DEFPY_NOSH (interface,
return ret;
}
-DEFPY (no_interface,
+DEFPY_YANG (no_interface,
no_interface_cmd,
"no interface IFNAME [vrf NAME$vrf_name]",
NO_STR
@@ -1428,7 +1425,7 @@ static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
/*
* XPath: /frr-interface:lib/interface/description
*/
-DEFPY (interface_desc,
+DEFPY_YANG (interface_desc,
interface_desc_cmd,
"description LINE...",
"Interface specific description\n"
@@ -1445,7 +1442,7 @@ DEFPY (interface_desc,
return ret;
}
-DEFPY (no_interface_desc,
+DEFPY_YANG (no_interface_desc,
no_interface_desc_cmd,
"no description",
NO_STR
diff --git a/lib/if.h b/lib/if.h
index 40e87c1e31..1fb0757db2 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -509,8 +509,7 @@ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_create_name(const char *name, vrf_id_t vrf_id);
/* Create new interface, adds to index list only */
-extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
- char *name);
+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(const void *matchaddr,
@@ -527,8 +526,8 @@ extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf);
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,
- char *optional_name);
+extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
+
/* Sets the index and adds to index list */
extern int if_set_index(struct interface *ifp, ifindex_t ifindex);
/* Sets the name and adds to name list */
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index cd7f79a04e..730c7ce130 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -25,6 +25,8 @@
#include <zebra.h>
+#include "lib/log.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -33,9 +35,9 @@ extern "C" {
* Generic IP address - union of IPv4 and IPv6 address.
*/
enum ipaddr_type_t {
- IPADDR_NONE = 0,
- IPADDR_V4 = 1, /* IPv4 */
- IPADDR_V6 = 2, /* IPv6 */
+ IPADDR_NONE = AF_UNSPEC,
+ IPADDR_V4 = AF_INET,
+ IPADDR_V6 = AF_INET6,
};
struct ipaddr {
@@ -59,6 +61,18 @@ struct ipaddr {
#define IPADDRSZ(p) \
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
+static inline int ipaddr_family(const struct ipaddr *ip)
+{
+ switch (ip->ipa_type) {
+ case IPADDR_V4:
+ return AF_INET;
+ case IPADDR_V6:
+ return AF_INET6;
+ default:
+ return AF_UNSPEC;
+ }
+}
+
static inline int str2ipaddr(const char *str, struct ipaddr *ip)
{
int ret;
@@ -84,15 +98,18 @@ static inline int str2ipaddr(const char *str, struct ipaddr *ip)
static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
{
buf[0] = '\0';
- if (ip) {
- if (IS_IPADDR_V4(ip))
- inet_ntop(AF_INET, &ip->ip.addr, buf, size);
- else if (IS_IPADDR_V6(ip))
- inet_ntop(AF_INET6, &ip->ip.addr, buf, size);
- }
+ if (ip)
+ inet_ntop(ip->ipa_type, &ip->ip.addr, buf, size);
return buf;
}
+#define IS_MAPPED_IPV6(A) \
+ ((A)->s6_addr32[0] == 0x00000000 \
+ ? ((A)->s6_addr32[1] == 0x00000000 \
+ ? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \
+ : 0) \
+ : 0)
+
/*
* Convert IPv4 address to IPv4-mapped IPv6 address which is of the
* form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
@@ -128,6 +145,35 @@ static inline bool ipaddr_isset(struct ipaddr *ip)
return (0 != memcmp(&a, ip, sizeof(struct ipaddr)));
}
+/*
+ * generic ordering comparison between IP addresses
+ */
+static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b)
+{
+ uint32_t va, vb;
+ va = a->ipa_type;
+ vb = b->ipa_type;
+ if (va != vb)
+ return (va < vb) ? -1 : 1;
+ switch (a->ipa_type) {
+ case IPADDR_V4:
+ va = ntohl(a->ipaddr_v4.s_addr);
+ vb = ntohl(b->ipaddr_v4.s_addr);
+ if (va != vb)
+ return (va < vb) ? -1 : 1;
+ return 0;
+ case IPADDR_V6:
+ return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6,
+ sizeof(a->ipaddr_v6));
+ default:
+ return 0;
+ }
+}
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pIA" (struct ipaddr *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libfrr.c b/lib/libfrr.c
index b3df7de6d3..2597eb61e2 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -105,6 +105,7 @@ static const struct option lo_always[] = {
{"daemon", no_argument, NULL, 'd'},
{"module", no_argument, NULL, 'M'},
{"profile", required_argument, NULL, 'F'},
+ {"pathspace", required_argument, NULL, 'N'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
{"log", required_argument, NULL, OPTION_LOG},
@@ -113,12 +114,13 @@ static const struct option lo_always[] = {
{"command-log-always", no_argument, NULL, OPTION_LOGGING},
{NULL}};
static const struct optspec os_always = {
- "hvdM:F:",
+ "hvdM:F:N:",
" -h, --help Display this help and exit\n"
" -v, --version Print program version\n"
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
" -F, --profile Use specified configuration profile\n"
+ " -N, --pathspace Insert prefix into config & socket paths\n"
" --vty_socket Override vty socket path\n"
" --moduledir Override modules directory\n"
" --log Set Logging to stdout, syslog, or file:<name>\n"
@@ -133,18 +135,16 @@ static const struct option lo_cfg_pid_dry[] = {
#ifdef HAVE_SQLITE3
{"db_file", required_argument, NULL, OPTION_DB_FILE},
#endif
- {"pathspace", required_argument, NULL, 'N'},
{"dryrun", no_argument, NULL, 'C'},
{"terminal", no_argument, NULL, 't'},
{NULL}};
static const struct optspec os_cfg_pid_dry = {
- "f:i:CtN:",
+ "f:i:Ct",
" -f, --config_file Set configuration file name\n"
" -i, --pid_file Set process identifier file name\n"
#ifdef HAVE_SQLITE3
" --db_file Set database file name\n"
#endif
- " -N, --pathspace Insert prefix into config & socket paths\n"
" -C, --dryrun Check configuration for validity and exit\n"
" -t, --terminal Open terminal session on stdio\n"
" -d -t Daemonize after terminal session ends\n",
@@ -428,8 +428,6 @@ static int frr_opt(int opt)
di->config_file = optarg;
break;
case 'N':
- if (di->flags & FRR_NO_CFG_PID_DRY)
- return 1;
if (di->pathspace) {
fprintf(stderr,
"-N/--pathspace option specified more than once!\n");
diff --git a/lib/linklist.c b/lib/linklist.c
index 272e153276..84dc6e1419 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -38,16 +38,30 @@ static void list_free_internal(struct list *l)
XFREE(MTYPE_LINK_LIST, l);
}
+
/* Allocate new listnode. Internal use only. */
-static struct listnode *listnode_new(void)
+static struct listnode *listnode_new(struct list *list, void *val)
{
- return XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode));
+ struct listnode *node;
+
+ /* if listnode memory is managed by the app then the val
+ * passed in is the listnode
+ */
+ if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
+ node = val;
+ node->prev = node->next = NULL;
+ } else {
+ node = XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode));
+ node->data = val;
+ }
+ return node;
}
/* Free listnode. */
-static void listnode_free(struct listnode *node)
+static void listnode_free(struct list *list, struct listnode *node)
{
- XFREE(MTYPE_LINK_NODE, node);
+ if (!(list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP))
+ XFREE(MTYPE_LINK_NODE, node);
}
struct listnode *listnode_add(struct list *list, void *val)
@@ -56,10 +70,9 @@ struct listnode *listnode_add(struct list *list, void *val)
assert(val != NULL);
- node = listnode_new();
+ node = listnode_new(list, val);
node->prev = list->tail;
- node->data = val;
if (list->head == NULL)
list->head = node;
@@ -78,10 +91,9 @@ void listnode_add_head(struct list *list, void *val)
assert(val != NULL);
- node = listnode_new();
+ node = listnode_new(list, val);
node->next = list->head;
- node->data = val;
if (list->head == NULL)
list->head = node;
@@ -97,15 +109,22 @@ bool listnode_add_sort_nodup(struct list *list, void *val)
struct listnode *n;
struct listnode *new;
int ret;
+ void *data;
assert(val != NULL);
+ if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
+ n = val;
+ data = n->data;
+ } else {
+ data = val;
+ }
+
if (list->cmp) {
for (n = list->head; n; n = n->next) {
- ret = (*list->cmp)(val, n->data);
+ ret = (*list->cmp)(data, n->data);
if (ret < 0) {
- new = listnode_new();
- new->data = val;
+ new = listnode_new(list, val);
new->next = n;
new->prev = n->prev;
@@ -124,14 +143,30 @@ bool listnode_add_sort_nodup(struct list *list, void *val)
}
}
- new = listnode_new();
- new->data = val;
+ new = listnode_new(list, val);
LISTNODE_ATTACH(list, new);
return true;
}
+struct list *list_dup(struct list *list)
+{
+ struct list *dup;
+ struct listnode *node;
+ void *data;
+
+ assert(list);
+
+ dup = list_new();
+ dup->cmp = list->cmp;
+ dup->del = list->del;
+ for (ALL_LIST_ELEMENTS_RO(list, node, data))
+ listnode_add(dup, data);
+
+ return dup;
+}
+
void listnode_add_sort(struct list *list, void *val)
{
struct listnode *n;
@@ -139,8 +174,8 @@ void listnode_add_sort(struct list *list, void *val)
assert(val != NULL);
- new = listnode_new();
- new->data = val;
+ new = listnode_new(list, val);
+ val = new->data;
if (list->cmp) {
for (n = list->head; n; n = n->next) {
@@ -177,8 +212,7 @@ struct listnode *listnode_add_after(struct list *list, struct listnode *pp,
assert(val != NULL);
- nn = listnode_new();
- nn->data = val;
+ nn = listnode_new(list, val);
if (pp == NULL) {
if (list->head)
@@ -212,8 +246,7 @@ struct listnode *listnode_add_before(struct list *list, struct listnode *pp,
assert(val != NULL);
- nn = listnode_new();
- nn->data = val;
+ nn = listnode_new(list, val);
if (pp == NULL) {
if (list->tail)
@@ -276,7 +309,7 @@ void list_delete_all_node(struct list *list)
next = node->next;
if (*list->del)
(*list->del)(node->data);
- listnode_free(node);
+ listnode_free(list, node);
}
list->head = list->tail = NULL;
list->count = 0;
@@ -336,7 +369,7 @@ void list_delete_node(struct list *list, struct listnode *node)
else
list->tail = node->prev;
list->count--;
- listnode_free(node);
+ listnode_free(list, node);
}
void list_sort(struct list *list, int (*cmp)(const void **, const void **))
diff --git a/lib/linklist.h b/lib/linklist.h
index 00cb9f8714..d8820c924d 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -43,6 +43,12 @@ struct list {
/* invariant: count is the number of listnodes in the list */
unsigned int count;
+ uint8_t flags;
+/* Indicates that listnode memory is managed by the application and
+ * doesn't need to be freed by this library via listnode_delete etc.
+ */
+#define LINKLIST_FLAG_NODE_MEM_BY_APP (1 << 0)
+
/*
* Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
* Used as definition of sorted for listnode_add_sort
@@ -60,10 +66,14 @@ struct list {
#define listhead(X) ((X) ? ((X)->head) : NULL)
#define listhead_unchecked(X) ((X)->head)
#define listtail(X) ((X) ? ((X)->tail) : NULL)
+#define listtail_unchecked(X) ((X)->tail)
#define listcount(X) ((X)->count)
#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
/* return X->data only if X and X->data are not NULL */
#define listgetdata(X) (assert(X), assert((X)->data != NULL), (X)->data)
+/* App is going to manage listnode memory */
+#define listset_app_node_mem(X) ((X)->flags |= LINKLIST_FLAG_NODE_MEM_BY_APP)
+#define listnode_init(X, val) ((X)->data = (val))
/*
* Create a new linked list.
@@ -95,7 +105,7 @@ extern struct listnode *listnode_add(struct list *list, void *data);
* list to operate on
*
* data
- * element to add
+ * If MEM_BY_APP is set this is listnode. Otherwise it is element to add.
*/
extern void listnode_add_head(struct list *list, void *data);
@@ -112,7 +122,7 @@ extern void listnode_add_head(struct list *list, void *data);
* list to operate on
*
* val
- * element to add
+ * If MEM_BY_APP is set this is listnode. Otherwise it is element to add.
*/
extern void listnode_add_sort(struct list *list, void *val);
@@ -128,7 +138,7 @@ extern void listnode_add_sort(struct list *list, void *val);
* listnode to insert after
*
* data
- * data to insert
+ * If MEM_BY_APP is set this is listnode. Otherwise it is element to add.
*
* Returns:
* pointer to newly created listnode that contains the inserted data
@@ -148,7 +158,7 @@ extern struct listnode *listnode_add_after(struct list *list,
* listnode to insert before
*
* data
- * data to insert
+ * If MEM_BY_APP is set this is listnode. Otherwise it is element to add.
*
* Returns:
* pointer to newly created listnode that contains the inserted data
@@ -313,10 +323,23 @@ extern void list_filter_out_nodes(struct list *list, bool (*cond)(void *data));
* list to operate on
*
* val
- * element to add
+ * If MEM_BY_APP is set this is listnode. Otherwise it is element to add.
*/
extern bool listnode_add_sort_nodup(struct list *list, void *val);
+
+/*
+ * Duplicate the specified list, creating a shallow copy of each of its
+ * elements.
+ *
+ * list
+ * list to duplicate
+ *
+ * Returns:
+ * the duplicated list
+ */
+extern struct list *list_dup(struct list *list);
+
/* List iteration macro.
* Usage: for (ALL_LIST_ELEMENTS (...) { ... }
* It is safe to delete the listnode using this macro.
diff --git a/lib/log.c b/lib/log.c
index 089a3e3a07..4054185019 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -273,8 +273,7 @@ void zlog_backtrace(int priority)
if (size <= 0 || (size_t)size > array_size(array)) {
flog_err_sys(
EC_LIB_SYSTEM_CALL,
- "Cannot get backtrace, returned invalid # of frames %d "
- "(valid range is between 1 and %lu)",
+ "Cannot get backtrace, returned invalid # of frames %d (valid range is between 1 and %lu)",
size, (unsigned long)(array_size(array)));
return;
}
@@ -301,8 +300,7 @@ void zlog_thread_info(int log_level)
if (tc)
zlog(log_level,
- "Current thread function %s, scheduled from "
- "file %s, line %u",
+ "Current thread function %s, scheduled from file %s, line %u",
tc->funcname, tc->schedfrom, tc->schedfrom_line);
else
zlog(log_level, "Current thread not known/applicable");
@@ -386,6 +384,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD),
DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE),
DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE),
+ DESC_ENTRY(ZEBRA_SR_POLICY_SET),
+ DESC_ENTRY(ZEBRA_SR_POLICY_DELETE),
+ DESC_ENTRY(ZEBRA_SR_POLICY_NOTIFY_STATUS),
DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
@@ -400,6 +401,10 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
DESC_ENTRY(ZEBRA_LOCAL_ES_ADD),
DESC_ENTRY(ZEBRA_LOCAL_ES_DEL),
+ DESC_ENTRY(ZEBRA_REMOTE_ES_VTEP_ADD),
+ DESC_ENTRY(ZEBRA_REMOTE_ES_VTEP_DEL),
+ DESC_ENTRY(ZEBRA_LOCAL_ES_EVI_ADD),
+ DESC_ENTRY(ZEBRA_LOCAL_ES_EVI_DEL),
DESC_ENTRY(ZEBRA_VNI_ADD),
DESC_ENTRY(ZEBRA_VNI_DEL),
DESC_ENTRY(ZEBRA_L3VNI_ADD),
@@ -446,7 +451,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES),
DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
DESC_ENTRY(ZEBRA_OPAQUE_REGISTER),
- DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER)};
+ DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER),
+ DESC_ENTRY(ZEBRA_NEIGH_DISCOVER)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
@@ -465,8 +471,7 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute)
for (i = 0; i < array_size(route_types); i++) {
if (zroute == route_types[i].type) {
zlog_warn(
- "internal error: route type table out of order "
- "while searching for %u, please notify developers",
+ "internal error: route type table out of order while searching for %u, please notify developers",
zroute);
return &route_types[i];
}
diff --git a/lib/log.h b/lib/log.h
index b65ae5d5d5..3d2f0ed829 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -64,13 +64,13 @@ struct message {
/* For logs which have error codes associated with them */
#define flog_err(ferr_id, format, ...) \
- zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
+ zlog_err("[EC %u] " format, ferr_id, ##__VA_ARGS__)
#define flog_err_sys(ferr_id, format, ...) \
flog_err(ferr_id, format, ##__VA_ARGS__)
#define flog_warn(ferr_id, format, ...) \
- zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
+ zlog_warn("[EC %u] " format, ferr_id, ##__VA_ARGS__)
#define flog(priority, ferr_id, format, ...) \
- zlog(priority, "[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
+ zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__)
extern void zlog_thread_info(int log_level);
diff --git a/lib/memory.c b/lib/memory.c
index 3a29404827..2c902d123b 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -157,8 +157,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
if (!mt) {
fprintf(eda->fp,
- "%s: showing active allocations in "
- "memory group %s\n",
+ "%s: showing active allocations in memory group %s\n",
eda->prefix, mg->name);
} else if (mt->n_alloc) {
diff --git a/lib/mpls.h b/lib/mpls.h
index 126dbf753d..8922a36664 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -129,6 +129,7 @@ enum lsp_types_t {
ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */
ZEBRA_LSP_ISIS_SR = 5,/* IS-IS Segment Routing LSP. */
ZEBRA_LSP_SHARP = 6, /* Identifier for test protocol */
+ ZEBRA_LSP_SRTE = 7, /* SR-TE LSP */
};
/* Functions for basic label operations. */
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index e1c0159fc5..98f359401e 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -379,20 +379,12 @@ struct ns *ns_lookup(ns_id_t ns_id)
return ns_lookup_internal(ns_id);
}
-void ns_walk_func(int (*func)(struct ns *,
- void *param_in,
- void **param_out),
- void *param_in,
- void **param_out)
+void ns_walk_func(int (*func)(struct ns *))
{
struct ns *ns = NULL;
- int ret;
- RB_FOREACH (ns, ns_head, &ns_tree) {
- ret = func(ns, param_in, param_out);
- if (ret == NS_WALK_STOP)
- return;
- }
+ RB_FOREACH (ns, ns_head, &ns_tree)
+ func(ns);
}
const char *ns_get_name(struct ns *ns)
@@ -592,33 +584,9 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
return ret;
}
-/* if relative link_nsid matches default netns,
- * then return default absolute netns value
- * otherwise, return NS_UNKNOWN
- */
-ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
-{
- struct ns *ns;
-
- ns = ns_lookup(ns_id_reference);
- if (!ns)
- return NS_UNKNOWN;
- if (ns->relative_default_ns != link_nsid)
- return NS_UNKNOWN;
- ns = ns_get_default();
- assert(ns);
- return ns->ns_id;
-}
-
ns_id_t ns_get_default_id(void)
{
if (default_ns)
return default_ns->ns_id;
return NS_DEFAULT_INTERNAL;
}
-
-struct ns *ns_get_default(void)
-{
- return default_ns;
-}
-
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 3496081d47..0ea72d03e1 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -152,11 +152,20 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
break;
}
+ if (next1->srte_color < next2->srte_color)
+ return -1;
+ if (next1->srte_color > next2->srte_color)
+ return 1;
+
ret = _nexthop_source_cmp(next1, next2);
if (ret != 0)
goto done;
if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
+ !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
+ return 0;
+
+ if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
return -1;
@@ -164,12 +173,18 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
!CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
return 1;
- if (next1->backup_idx < next2->backup_idx)
+ if (next1->backup_num == 0 && next2->backup_num == 0)
+ goto done;
+
+ if (next1->backup_num < next2->backup_num)
return -1;
- if (next1->backup_idx > next2->backup_idx)
+ if (next1->backup_num > next2->backup_num)
return 1;
+ ret = memcmp(next1->backup_idx,
+ next2->backup_idx, next1->backup_num);
+
done:
return ret;
}
@@ -515,11 +530,12 @@ struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
return next;
}
-unsigned int nexthop_level(struct nexthop *nexthop)
+unsigned int nexthop_level(const struct nexthop *nexthop)
{
unsigned int rv = 0;
- for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
+ for (const struct nexthop *par = nexthop->rparent;
+ par; par = par->rparent)
rv++;
return rv;
@@ -529,14 +545,15 @@ unsigned int nexthop_level(struct nexthop *nexthop)
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
{
uint32_t key = 0x45afe398;
- uint32_t val;
+ int i;
key = jhash_3words(nexthop->type, nexthop->vrf_id,
nexthop->nh_label_type, key);
if (nexthop->nh_label) {
int labels = nexthop->nh_label->num_labels;
- int i = 0;
+
+ i = 0;
while (labels >= 3) {
key = jhash_3words(nexthop->nh_label->label[i],
@@ -559,14 +576,35 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
key = jhash_1word(nexthop->nh_label->label[i], key);
}
- val = 0;
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
- val = (uint32_t)nexthop->backup_idx;
-
- key = jhash_3words(nexthop->ifindex,
- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val,
+ key = jhash_2words(nexthop->ifindex,
+ CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
key);
+ /* Include backup nexthops, if present */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ int backups = nexthop->backup_num;
+
+ i = 0;
+
+ while (backups >= 3) {
+ key = jhash_3words(nexthop->backup_idx[i],
+ nexthop->backup_idx[i + 1],
+ nexthop->backup_idx[i + 2], key);
+ backups -= 3;
+ i += 3;
+ }
+
+ while (backups >= 2) {
+ key = jhash_2words(nexthop->backup_idx[i],
+ nexthop->backup_idx[i + 1], key);
+ backups -= 2;
+ i += 2;
+ }
+
+ if (backups >= 1)
+ key = jhash_1word(nexthop->backup_idx[i], key);
+ }
+
return key;
}
@@ -604,7 +642,13 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
copy->type = nexthop->type;
copy->flags = nexthop->flags;
copy->weight = nexthop->weight;
- copy->backup_idx = nexthop->backup_idx;
+
+ assert(nexthop->backup_num < NEXTHOP_MAX_BACKUPS);
+ copy->backup_num = nexthop->backup_num;
+ if (copy->backup_num > 0)
+ memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num);
+
+ copy->srte_color = nexthop->srte_color;
memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
@@ -621,7 +665,7 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
nexthop_copy_no_recurse(copy, nexthop, rparent);
/* Bit of a special case here, we need to handle the case
- * of a nexthop resolving to agroup. Hence, we need to
+ * of a nexthop resolving to a group. Hence, we need to
* use a nexthop_group API.
*/
if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -647,6 +691,67 @@ struct nexthop *nexthop_dup(const struct nexthop *nexthop,
}
/*
+ * Parse one or more backup index values, as comma-separated numbers,
+ * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS
+ * in size. Mails back the number of values converted, and returns 0 on
+ * success, <0 if an error in parsing.
+ */
+int nexthop_str2backups(const char *str, int *num_backups,
+ uint8_t *backups)
+{
+ char *ostr; /* copy of string (start) */
+ char *lstr; /* working copy of string */
+ char *nump; /* pointer to next segment */
+ char *endp; /* end pointer */
+ int i, ret;
+ uint8_t tmp[NEXTHOP_MAX_BACKUPS];
+ uint32_t lval;
+
+ /* Copy incoming string; the parse is destructive */
+ lstr = ostr = XSTRDUP(MTYPE_TMP, str);
+ *num_backups = 0;
+ ret = 0;
+
+ for (i = 0; i < NEXTHOP_MAX_BACKUPS && lstr; i++) {
+ nump = strsep(&lstr, ",");
+ lval = strtoul(nump, &endp, 10);
+
+ /* Format check */
+ if (*endp != '\0') {
+ ret = -1;
+ break;
+ }
+
+ /* Empty value */
+ if (endp == nump) {
+ ret = -1;
+ break;
+ }
+
+ /* Limit to one octet */
+ if (lval > 255) {
+ ret = -1;
+ break;
+ }
+
+ tmp[i] = lval;
+ }
+
+ /* Excess values */
+ if (ret == 0 && i == NEXTHOP_MAX_BACKUPS && lstr)
+ ret = -1;
+
+ if (ret == 0) {
+ *num_backups = i;
+ memcpy(backups, tmp, i);
+ }
+
+ XFREE(MTYPE_TMP, ostr);
+
+ return ret;
+}
+
+/*
* nexthop printing variants:
* %pNHvv
* via 1.2.3.4
diff --git a/lib/nexthop.h b/lib/nexthop.h
index eda88efc08..cadcea1f41 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -65,6 +65,12 @@ enum nh_encap_type {
NET_VXLAN = 100, /* value copied from FPM_NH_ENCAP_VXLAN. */
};
+/* Fixed limit on the number of backup nexthops per primary nexthop */
+#define NEXTHOP_MAX_BACKUPS 8
+
+/* Backup index value is limited */
+#define NEXTHOP_BACKUP_IDX_MAX 255
+
/* Nexthop structure. */
struct nexthop {
struct nexthop *next;
@@ -92,6 +98,7 @@ struct nexthop {
*/
#define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */
#define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */
+#define NEXTHOP_FLAG_SRTE (1 << 7) /* SR-TE color used for BGP traffic */
#define NEXTHOP_IS_ACTIVE(flags) \
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
@@ -124,20 +131,21 @@ struct nexthop {
/* Weight of the nexthop ( for unequal cost ECMP ) */
uint8_t weight;
- /* Index of a corresponding backup nexthop in a backup list;
+ /* Count and index of corresponding backup nexthop(s) in a backup list;
* only meaningful if the HAS_BACKUP flag is set.
*/
- uint8_t backup_idx;
+ uint8_t backup_num;
+ uint8_t backup_idx[NEXTHOP_MAX_BACKUPS];
/* Encapsulation information. */
enum nh_encap_type nh_encap_type;
union {
vni_t vni;
} nh_encap;
-};
-/* Backup index value is limited */
-#define NEXTHOP_BACKUP_IDX_MAX 255
+ /* SR-TE color used for matching SR-TE policies */
+ uint32_t srte_color;
+};
/* Utility to append one nexthop to another. */
#define NEXTHOP_APPEND(to, new) \
@@ -216,7 +224,7 @@ extern const char *nexthop2str(const struct nexthop *nexthop,
extern struct nexthop *nexthop_next(const struct nexthop *nexthop);
extern struct nexthop *
nexthop_next_active_resolved(const struct nexthop *nexthop);
-extern unsigned int nexthop_level(struct nexthop *nexthop);
+extern unsigned int nexthop_level(const struct nexthop *nexthop);
/* Copies to an already allocated nexthop struct */
extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
struct nexthop *rparent);
@@ -231,6 +239,15 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop,
extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
struct nexthop *rparent);
+/*
+ * Parse one or more backup index values, as comma-separated numbers,
+ * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS
+ * in size. Mails back the number of values converted, and returns 0 on
+ * success, <0 if an error in parsing.
+ */
+int nexthop_str2backups(const char *str, int *num_backups,
+ uint8_t *backups);
+
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pNH" (struct nexthop *)
#endif
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 4f0c72af27..8ae001e42a 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -43,12 +43,9 @@ struct nexthop_hold {
char *intf;
char *labels;
uint32_t weight;
- int backup_idx; /* Index of backup nexthop, if >= 0 */
+ char *backup_str;
};
-/* Invalid/unset value for nexthop_hold's backup_idx */
-#define NHH_BACKUP_IDX_INVALID -1
-
struct nexthop_group_hooks {
void (*new)(const char *name);
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -677,7 +674,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
const char *intf, const char *labels,
- const uint32_t weight, int backup_idx)
+ const uint32_t weight,
+ const char *backup_str)
{
struct nexthop_hold *nh;
@@ -694,7 +692,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->weight = weight;
- nh->backup_idx = backup_idx;
+ if (backup_str)
+ nh->backup_str = XSTRDUP(MTYPE_TMP, backup_str);
listnode_add_sort(nhgc->nhg_list, nh);
}
@@ -741,10 +740,11 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
const char *intf, const char *name,
const char *labels, int *lbl_ret,
- uint32_t weight, int backup_idx)
+ uint32_t weight, const char *backup_str)
{
int ret = 0;
struct vrf *vrf;
+ int num;
memset(nhop, 0, sizeof(*nhop));
@@ -800,13 +800,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->weight = weight;
- if (backup_idx != NHH_BACKUP_IDX_INVALID) {
- /* Validate index value */
- if (backup_idx > NEXTHOP_BACKUP_IDX_MAX)
+ if (backup_str) {
+ /* Parse backup indexes */
+ ret = nexthop_str2backups(backup_str,
+ &num, nhop->backup_idx);
+ if (ret == 0) {
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nhop->backup_num = num;
+ } else
return false;
-
- SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
- nhop->backup_idx = backup_idx;
}
return true;
@@ -820,7 +822,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
{
return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
nhh->nhvrf_name, nhh->labels, NULL,
- nhh->weight, nhh->backup_idx));
+ nhh->weight, nhh->backup_str));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -833,7 +835,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nexthop-vrf NAME$vrf_name \
|label WORD \
|weight (1-255) \
- |backup-idx$bi_str (0-254)$idx \
+ |backup-idx WORD \
}]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
@@ -847,19 +849,26 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"One or more labels in the range (16-1048575) separated by '/'\n"
"Weight to be used by the nexthop for purposes of ECMP\n"
"Weight value to be used\n"
- "Backup nexthop index in another group\n"
- "Nexthop index value\n")
+ "Specify backup nexthop indexes in another group\n"
+ "One or more indexes in the range (0-254) separated by ','\n")
{
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct nexthop nhop;
struct nexthop *nh;
int lbl_ret = 0;
bool legal;
- int backup_idx = idx;
+ int num;
+ uint8_t backups[NEXTHOP_MAX_BACKUPS];
bool yes = !no;
- if (bi_str == NULL)
- backup_idx = NHH_BACKUP_IDX_INVALID;
+ /* Pre-parse backup string to validate */
+ if (backup_idx) {
+ lbl_ret = nexthop_str2backups(backup_idx, &num, backups);
+ if (lbl_ret < 0) {
+ vty_out(vty, "%% Invalid backups\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
&lbl_ret, weight, backup_idx);
@@ -943,10 +952,11 @@ static struct cmd_node nexthop_group_node = {
.config_write = nexthop_group_write,
};
-void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
+void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
{
char buf[100];
struct vrf *vrf;
+ int i;
vty_out(vty, "nexthop ");
@@ -976,7 +986,7 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
if (nh->vrf_id != VRF_DEFAULT) {
vrf = vrf_lookup_by_id(nh->vrf_id);
- vty_out(vty, " nexthop-vrf %s", vrf->name);
+ vty_out(vty, " nexthop-vrf %s", VRF_LOGNAME(vrf));
}
if (nh->nh_label && nh->nh_label->num_labels > 0) {
@@ -991,16 +1001,22 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
- vty_out(vty, " backup-idx %d", nh->backup_idx);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ vty_out(vty, " backup-idx %d", nh->backup_idx[0]);
+
+ for (i = 1; i < nh->backup_num; i++)
+ vty_out(vty, ",%d", nh->backup_idx[i]);
+ }
vty_out(vty, "\n");
}
-void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh)
+void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh)
{
char buf[100];
struct vrf *vrf;
+ json_object *json_backups = NULL;
+ int i;
switch (nh->type) {
case NEXTHOP_TYPE_IFINDEX:
@@ -1047,12 +1063,19 @@ void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh)
if (nh->weight)
json_object_int_add(j, "weight", nh->weight);
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
- json_object_int_add(j, "backupIdx", nh->backup_idx);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ json_backups = json_object_new_array();
+ for (i = 0; i < nh->backup_num; i++)
+ json_object_array_add(
+ json_backups,
+ json_object_new_int(nh->backup_idx[i]));
+
+ json_object_object_add(j, "backupIdx", json_backups);
+ }
}
static void nexthop_group_write_nexthop_internal(struct vty *vty,
- struct nexthop_hold *nh)
+ const struct nexthop_hold *nh)
{
char buf[100];
@@ -1073,8 +1096,8 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
- if (nh->backup_idx != NHH_BACKUP_IDX_INVALID)
- vty_out(vty, " backup-idx %d", nh->backup_idx);
+ if (nh->backup_str)
+ vty_out(vty, " backup-idx %s", nh->backup_str);
vty_out(vty, "\n");
}
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 9888dad982..0b5ac91bb2 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -135,9 +135,11 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1,
extern struct nexthop_group_cmd *nhgc_find(const char *name);
-extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
+extern void nexthop_group_write_nexthop(struct vty *vty,
+ const struct nexthop *nh);
-extern void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh);
+extern void nexthop_group_json_nexthop(json_object *j,
+ const struct nexthop *nh);
/* Return the number of nexthops in this nhg */
extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
diff --git a/lib/northbound.c b/lib/northbound.c
index 48b8499bfc..29e843a84e 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -680,8 +680,12 @@ int nb_candidate_commit_prepare(struct nb_context *context,
RB_INIT(nb_config_cbs, &changes);
nb_config_diff(running_config, candidate, &changes);
- if (RB_EMPTY(nb_config_cbs, &changes))
+ if (RB_EMPTY(nb_config_cbs, &changes)) {
+ snprintf(
+ errmsg, errmsg_len,
+ "No changes to apply were found during preparation phase");
return NB_ERR_NO_CHANGES;
+ }
if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
errmsg_len)
@@ -707,23 +711,21 @@ int nb_candidate_commit_prepare(struct nb_context *context,
errmsg_len);
}
-void nb_candidate_commit_abort(struct nb_transaction *transaction)
+void nb_candidate_commit_abort(struct nb_transaction *transaction, char *errmsg,
+ size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_ABORT, transaction, errmsg,
- sizeof(errmsg));
+ errmsg_len);
nb_transaction_free(transaction);
}
void nb_candidate_commit_apply(struct nb_transaction *transaction,
- bool save_transaction, uint32_t *transaction_id)
+ bool save_transaction, uint32_t *transaction_id,
+ char *errmsg, size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_APPLY, transaction, errmsg,
- sizeof(errmsg));
- nb_transaction_apply_finish(transaction, errmsg, sizeof(errmsg));
+ errmsg_len);
+ nb_transaction_apply_finish(transaction, errmsg, errmsg_len);
/* Replace running by candidate. */
transaction->config->version++;
@@ -754,9 +756,9 @@ int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
*/
if (ret == NB_OK)
nb_candidate_commit_apply(transaction, save_transaction,
- transaction_id);
+ transaction_id, errmsg, errmsg_len);
else if (transaction != NULL)
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, errmsg_len);
return ret;
}
@@ -2046,18 +2048,21 @@ void *nb_running_unset_entry(const struct lyd_node *dnode)
return entry;
}
-void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
- bool abort_if_not_found)
+static void *nb_running_get_entry_worker(const struct lyd_node *dnode,
+ const char *xpath,
+ bool abort_if_not_found,
+ bool rec_search)
{
const struct lyd_node *orig_dnode = dnode;
char xpath_buf[XPATH_MAXLEN];
+ bool rec_flag = true;
assert(dnode || xpath);
if (!dnode)
dnode = yang_dnode_get(running_config->dnode, xpath);
- while (dnode) {
+ while (rec_flag && dnode) {
struct nb_config_entry *config, s;
yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
@@ -2065,6 +2070,8 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
if (config)
return config->entry;
+ rec_flag = rec_search;
+
dnode = dnode->parent;
}
@@ -2078,6 +2085,20 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
abort();
}
+void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
+ bool abort_if_not_found)
+{
+ return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found,
+ true);
+}
+
+void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
+ const char *xpath, bool abort_if_not_found)
+{
+ return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found,
+ false);
+}
+
/* Logging functions. */
const char *nb_event_name(enum nb_event event)
{
diff --git a/lib/northbound.h b/lib/northbound.h
index bd57013f59..fa5ac5616c 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -910,8 +910,15 @@ extern int nb_candidate_commit_prepare(struct nb_context *context,
*
* transaction
* Candidate configuration to abort. It's consumed by this function.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
-extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
+extern void nb_candidate_commit_abort(struct nb_transaction *transaction,
+ char *errmsg, size_t errmsg_len);
/*
* Commit a previously created configuration transaction.
@@ -925,10 +932,17 @@ extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
*
* transaction_id
* Optional output parameter providing the ID of the committed transaction.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
bool save_transaction,
- uint32_t *transaction_id);
+ uint32_t *transaction_id, char *errmsg,
+ size_t errmsg_len);
/*
* Create a new transaction to commit a candidate configuration. This is a
@@ -1165,6 +1179,14 @@ extern void *nb_running_get_entry(const struct lyd_node *dnode,
const char *xpath, bool abort_if_not_found);
/*
+ * Same as 'nb_running_get_entry', but doesn't search within parent nodes
+ * recursively if an user point is not found.
+ */
+extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
+ const char *xpath,
+ bool abort_if_not_found);
+
+/*
* Return a human-readable string representing a northbound event.
*
* event
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 105fc83cef..2f6aef5398 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -53,6 +53,108 @@ static void vty_show_nb_errors(struct vty *vty, int error, const char *errmsg)
vty_out(vty, "Error description: %s\n", errmsg);
}
+static int nb_cli_classic_commit(struct vty *vty)
+{
+ struct nb_context context = {};
+ char errmsg[BUFSIZ] = {0};
+ int ret;
+
+ context.client = NB_CLIENT_CLI;
+ context.user = vty;
+ ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL,
+ NULL, errmsg, sizeof(errmsg));
+ if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
+ vty_out(vty, "%% Configuration failed.\n\n");
+ vty_show_nb_errors(vty, ret, errmsg);
+ if (vty->t_pending_commit)
+ vty_out(vty,
+ "The following commands were dynamically grouped into the same transaction and rejected:\n%s",
+ vty->pending_cmds_buf);
+
+ /* Regenerate candidate for consistency. */
+ nb_config_replace(vty->candidate_config, running_config, true);
+ return CMD_WARNING_CONFIG_FAILED;
+ } else if (strlen(errmsg) > 0)
+ /* Successful commit. Print warnings (if any). */
+ vty_out(vty, "%s\n", errmsg);
+
+ return CMD_SUCCESS;
+}
+
+static void nb_cli_pending_commit_clear(struct vty *vty)
+{
+ THREAD_TIMER_OFF(vty->t_pending_commit);
+ vty->backoff_cmd_count = 0;
+ XFREE(MTYPE_TMP, vty->pending_cmds_buf);
+ vty->pending_cmds_buflen = 0;
+ vty->pending_cmds_bufpos = 0;
+}
+
+static int nb_cli_pending_commit_cb(struct thread *thread)
+{
+ struct vty *vty = THREAD_ARG(thread);
+
+ (void)nb_cli_classic_commit(vty);
+ nb_cli_pending_commit_clear(vty);
+
+ return 0;
+}
+
+void nb_cli_pending_commit_check(struct vty *vty)
+{
+ if (vty->t_pending_commit) {
+ (void)nb_cli_classic_commit(vty);
+ nb_cli_pending_commit_clear(vty);
+ }
+}
+
+static bool nb_cli_backoff_start(struct vty *vty)
+{
+ struct timeval now, delta;
+
+ /*
+ * Start the configuration backoff timer only if 100 YANG-modeled
+ * commands or more were entered within the last second.
+ */
+ monotime(&now);
+ if (monotime_since(&vty->backoff_start, &delta) >= 1000000) {
+ vty->backoff_start = now;
+ vty->backoff_cmd_count = 1;
+ return false;
+ }
+ if (++vty->backoff_cmd_count < 100)
+ return false;
+
+ return true;
+}
+
+static int nb_cli_schedule_command(struct vty *vty)
+{
+ /* Append command to dynamically sized buffer of scheduled commands. */
+ if (!vty->pending_cmds_buf) {
+ vty->pending_cmds_buflen = 4096;
+ vty->pending_cmds_buf =
+ XCALLOC(MTYPE_TMP, vty->pending_cmds_buflen);
+ }
+ if ((strlen(vty->buf) + 3)
+ > (vty->pending_cmds_buflen - vty->pending_cmds_bufpos)) {
+ vty->pending_cmds_buflen *= 2;
+ vty->pending_cmds_buf =
+ XREALLOC(MTYPE_TMP, vty->pending_cmds_buf,
+ vty->pending_cmds_buflen);
+ }
+ strlcat(vty->pending_cmds_buf, "- ", vty->pending_cmds_buflen);
+ vty->pending_cmds_bufpos = strlcat(vty->pending_cmds_buf, vty->buf,
+ vty->pending_cmds_buflen);
+
+ /* Schedule the commit operation. */
+ THREAD_TIMER_OFF(vty->t_pending_commit);
+ thread_add_timer_msec(master, nb_cli_pending_commit_cb, vty, 100,
+ &vty->t_pending_commit);
+
+ return CMD_SUCCESS;
+}
+
void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
enum nb_operation operation, const char *value)
{
@@ -76,7 +178,6 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
{
char xpath_base[XPATH_MAXLEN] = {};
bool error = false;
- int ret;
VTY_CHECK_XPATH;
@@ -95,6 +196,7 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
struct nb_node *nb_node;
char xpath[XPATH_MAXLEN];
struct yang_data *data;
+ int ret;
/* Handle relative XPaths. */
memset(xpath, 0, sizeof(xpath));
@@ -158,25 +260,19 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
}
- /* Do an implicit "commit" when using the classic CLI mode. */
+ /*
+ * Do an implicit commit when using the classic CLI mode.
+ *
+ * NOTE: the implicit commit might be scheduled to run later when
+ * too many commands are being sent at the same time. This is a
+ * protection mechanism where multiple commands are grouped into the
+ * same configuration transaction, allowing them to be processed much
+ * faster.
+ */
if (frr_get_cli_mode() == FRR_CLI_CLASSIC) {
- struct nb_context context = {};
- char errmsg[BUFSIZ] = {0};
-
- context.client = NB_CLIENT_CLI;
- context.user = vty;
- ret = nb_candidate_commit(&context, vty->candidate_config,
- false, NULL, NULL, errmsg,
- sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
- vty_out(vty, "%% Configuration failed.\n\n");
- vty_show_nb_errors(vty, ret, errmsg);
-
- /* Regenerate candidate for consistency. */
- nb_config_replace(vty->candidate_config, running_config,
- true);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (vty->t_pending_commit || nb_cli_backoff_start(vty))
+ return nb_cli_schedule_command(vty);
+ return nb_cli_classic_commit(vty);
}
return CMD_SUCCESS;
@@ -224,11 +320,14 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
&context, vty->confirmed_commit_rollback, true,
"Rollback to previous configuration - confirmed commit has timed out",
&transaction_id, errmsg, sizeof(errmsg));
- if (ret == NB_OK)
+ if (ret == NB_OK) {
vty_out(vty,
"Rollback performed successfully (Transaction ID #%u).\n",
transaction_id);
- else {
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
+ } else {
vty_out(vty,
"Failed to rollback to previous configuration.\n\n");
vty_show_nb_errors(vty, ret, errmsg);
@@ -313,6 +412,9 @@ static int nb_cli_commit(struct vty *vty, bool force,
vty_out(vty,
"%% Configuration committed successfully (Transaction ID #%u).\n\n",
transaction_id);
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty, "%% No configuration changes to commit.\n\n");
@@ -1572,6 +1674,9 @@ static int nb_cli_rollback_configuration(struct vty *vty,
case NB_OK:
vty_out(vty,
"%% Configuration was successfully rolled back.\n\n");
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty,
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index b2d8c8f035..112d62efda 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -108,6 +108,14 @@ extern int nb_cli_rpc(const char *xpath, struct list *input,
extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+/*
+ * Perform pending commit, if any.
+ *
+ * vty
+ * The vty context.
+ */
+extern void nb_cli_pending_commit_check(struct vty *vty);
+
/* Prototypes of internal functions. */
extern void nb_cli_show_config_prepare(struct nb_config *config,
bool with_defaults);
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index a3aaf02f08..1f480f3d02 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -375,8 +375,10 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -400,8 +402,9 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 83d7e0ce95..f35b4bb31b 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -677,11 +677,13 @@ class NorthboundImpl
switch (phase) {
case frr::CommitRequest::VALIDATE:
+ zlog_debug("`-> Performing VALIDATE");
ret = nb_candidate_validate(
&context, candidate->config, errmsg,
sizeof(errmsg));
break;
case frr::CommitRequest::PREPARE:
+ zlog_debug("`-> Performing PREPARE");
ret = nb_candidate_commit_prepare(
&context, candidate->config,
comment.c_str(),
@@ -689,15 +691,20 @@ class NorthboundImpl
sizeof(errmsg));
break;
case frr::CommitRequest::ABORT:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_abort(
- candidate->transaction);
+ candidate->transaction, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::APPLY:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_apply(
candidate->transaction, true,
- &transaction_id);
+ &transaction_id, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::ALL:
+ zlog_debug("`-> Performing ALL");
ret = nb_candidate_commit(
&context, candidate->config, true,
comment.c_str(), &transaction_id,
@@ -735,12 +742,20 @@ class NorthboundImpl
grpc::StatusCode::INTERNAL, errmsg);
break;
}
+
+ if (nb_dbg_client_grpc)
+ zlog_debug("`-> Result: %s (message: '%s')",
+ nb_err_name((enum nb_error)ret),
+ errmsg);
+
if (ret == NB_OK) {
// Response: uint32 transaction_id = 1;
if (transaction_id)
tag->response.set_transaction_id(
transaction_id);
}
+ if (strlen(errmsg) > 0)
+ tag->response.set_error_message(errmsg);
tag->responder.Finish(tag->response, status, tag);
tag->state = FINISH;
@@ -1281,10 +1296,13 @@ class NorthboundImpl
void delete_candidate(struct candidate *candidate)
{
+ char errmsg[BUFSIZ] = {0};
+
_candidates.erase(candidate->id);
nb_config_free(candidate->config);
if (candidate->transaction)
- nb_candidate_commit_abort(candidate->transaction);
+ nb_candidate_commit_abort(candidate->transaction,
+ errmsg, sizeof(errmsg));
}
struct candidate *get_candidate(uint32_t candidate_id)
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 500203173c..2209b19c14 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -329,8 +329,10 @@ static int frr_sr_config_change_cb_apply(sr_session_ctx_t *session,
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -343,8 +345,9 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session,
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
diff --git a/lib/ns.h b/lib/ns.h
index 286ff5b295..20e0a38e3b 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -53,11 +53,6 @@ struct ns {
/* Identifier, mapped on the NSID value */
ns_id_t internal_ns_id;
- /* Identifier, value of NSID of default netns,
- * relative value in that local netns
- */
- ns_id_t relative_default_ns;
-
/* Name */
char *name;
@@ -125,14 +120,7 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id);
extern char *ns_netns_pathname(struct vty *vty, const char *name);
/* Parse and execute a function on all the NETNS */
-#define NS_WALK_CONTINUE 0
-#define NS_WALK_STOP 1
-
-extern void ns_walk_func(int (*func)(struct ns *,
- void *,
- void **),
- void *param_in,
- void **param_out);
+extern void ns_walk_func(int (*func)(struct ns *));
/* API to get the NETNS name, from the ns pointer */
extern const char *ns_get_name(struct ns *ns);
@@ -186,9 +174,7 @@ extern struct ns *ns_lookup_name(const char *name);
*/
extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
-extern ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid);
extern void ns_disable(struct ns *ns);
-extern struct ns *ns_get_default(void);
#ifdef __cplusplus
}
diff --git a/lib/pbr.h b/lib/pbr.h
index cf6ac41d32..fd183d7115 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -49,6 +49,10 @@ struct pbr_filter {
#define PBR_FILTER_PROTO (1 << 5)
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
+#define PBR_FILTER_DSFIELD (1 << 8)
+
+#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
+#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
/* Source and Destination IP address with masks. */
struct prefix src_ip;
@@ -58,6 +62,9 @@ struct pbr_filter {
uint16_t src_port;
uint16_t dst_port;
+ /* Filter by Differentiated Services field */
+ uint8_t dsfield; /* DSCP (6 bits) & ECN (2 bits) */
+
/* Filter with fwmark */
uint32_t fwmark;
};
diff --git a/lib/prefix.c b/lib/prefix.c
index 0900100be3..697e1a6239 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -22,6 +22,7 @@
#include <zebra.h>
#include "prefix.h"
+#include "ipaddr.h"
#include "vty.h"
#include "sockunion.h"
#include "memory.h"
@@ -1316,6 +1317,26 @@ char *esi_to_str(const esi_t *esi, char *buf, int size)
return ptr;
}
+printfrr_ext_autoreg_p("EA", printfrr_ea)
+static ssize_t printfrr_ea(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const struct ethaddr *mac = ptr;
+
+ prefix_mac2str(mac, buf, bsz);
+ return 2;
+}
+
+printfrr_ext_autoreg_p("IA", printfrr_ia)
+static ssize_t printfrr_ia(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const struct ipaddr *ipa = ptr;
+
+ ipaddr2str(ipa, buf, bsz);
+ return 2;
+}
+
printfrr_ext_autoreg_p("I4", printfrr_i4)
static ssize_t printfrr_i4(char *buf, size_t bsz, const char *fmt,
int prec, const void *ptr)
diff --git a/lib/prefix.h b/lib/prefix.h
index 0bd457cc23..400f07386f 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -43,9 +43,36 @@ extern "C" {
#define ETH_ALEN 6
#endif
+/* EVPN route types. */
+typedef enum {
+ BGP_EVPN_AD_ROUTE = 1, /* Ethernet Auto-Discovery (A-D) route */
+ BGP_EVPN_MAC_IP_ROUTE, /* MAC/IP Advertisement route */
+ BGP_EVPN_IMET_ROUTE, /* Inclusive Multicast Ethernet Tag route */
+ BGP_EVPN_ES_ROUTE, /* Ethernet Segment route */
+ BGP_EVPN_IP_PREFIX_ROUTE, /* IP Prefix route */
+} bgp_evpn_route_type;
+
+/* value of first byte of ESI */
+#define ESI_TYPE_ARBITRARY 0 /* */
+#define ESI_TYPE_LACP 1 /* <> */
+#define ESI_TYPE_BRIDGE 2 /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */
+#define ESI_TYPE_MAC 3 /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */
+#define ESI_TYPE_ROUTER 4 /* <RouterId-4B>:<Local Discriminator Value-4B> */
+#define ESI_TYPE_AS 5 /* <AS-4B>:<Local Discriminator Value-4B> */
+
+#define MAX_ESI {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+
+#define EVPN_ETH_TAG_BYTES 4
#define ESI_BYTES 10
#define ESI_STR_LEN (3 * ESI_BYTES)
+/* Maximum number of VTEPs per-ES -
+ * XXX - temporary limit for allocating strings etc.
+ */
+#define ES_VTEP_MAX_CNT 10
+#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * 16)
+
#define ETHER_ADDR_STRLEN (3*ETH_ALEN)
/*
* there isn't a portable ethernet address type. We define our
@@ -64,12 +91,13 @@ struct ethaddr {
#define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8)
typedef struct esi_t_ {
- uint8_t val[10];
+ uint8_t val[ESI_BYTES];
} esi_t;
struct evpn_ead_addr {
esi_t esi;
uint32_t eth_tag;
+ struct ipaddr ip;
};
struct evpn_macip_addr {
@@ -217,39 +245,45 @@ struct prefix_evpn {
static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp)
{
- if (evp->prefix.route_type == 2)
+ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
+ return IS_IPADDR_NONE(&(evp)->prefix.ead_addr.ip);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
return IS_IPADDR_NONE(&(evp)->prefix.macip_addr.ip);
- if (evp->prefix.route_type == 3)
+ if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)
return IS_IPADDR_NONE(&(evp)->prefix.imet_addr.ip);
- if (evp->prefix.route_type == 4)
+ if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE)
return IS_IPADDR_NONE(&(evp)->prefix.es_addr.ip);
- if (evp->prefix.route_type == 5)
+ if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip);
return 0;
}
static inline int is_evpn_prefix_ipaddr_v4(const struct prefix_evpn *evp)
{
- if (evp->prefix.route_type == 2)
+ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
+ return IS_IPADDR_V4(&(evp)->prefix.ead_addr.ip);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
return IS_IPADDR_V4(&(evp)->prefix.macip_addr.ip);
- if (evp->prefix.route_type == 3)
+ if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)
return IS_IPADDR_V4(&(evp)->prefix.imet_addr.ip);
- if (evp->prefix.route_type == 4)
+ if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE)
return IS_IPADDR_V4(&(evp)->prefix.es_addr.ip);
- if (evp->prefix.route_type == 5)
+ if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip);
return 0;
}
static inline int is_evpn_prefix_ipaddr_v6(const struct prefix_evpn *evp)
{
- if (evp->prefix.route_type == 2)
+ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
+ return IS_IPADDR_V6(&(evp)->prefix.ead_addr.ip);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
return IS_IPADDR_V6(&(evp)->prefix.macip_addr.ip);
- if (evp->prefix.route_type == 3)
+ if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)
return IS_IPADDR_V6(&(evp)->prefix.imet_addr.ip);
- if (evp->prefix.route_type == 4)
+ if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE)
return IS_IPADDR_V6(&(evp)->prefix.es_addr.ip);
- if (evp->prefix.route_type == 5)
+ if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip);
return 0;
}
@@ -555,6 +589,8 @@ static inline int is_default_host_route(const struct prefix *p)
}
#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pEA" (struct ethaddr *)
+
#pragma FRR printfrr_ext "%pI4" (struct in_addr *)
#pragma FRR printfrr_ext "%pI4" (in_addr_t *)
diff --git a/lib/privs.c b/lib/privs.c
index eb0dbe0783..5c7e1240e2 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -558,8 +558,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs)
/* nonsensical to have gotten here but not have capabilities */
if (!zprivs_state.syscaps_p) {
fprintf(stderr,
- "%s: capabilities enabled, "
- "but no valid capabilities supplied\n",
+ "%s: capabilities enabled, but no valid capabilities supplied\n",
__func__);
}
diff --git a/lib/privs.h b/lib/privs.h
index db5707d675..18ba8e8888 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -24,6 +24,7 @@
#define _ZEBRA_PRIVS_H
#include <pthread.h>
+#include <stdint.h>
#include "lib/queue.h"
#ifdef __cplusplus
diff --git a/lib/route_types.pl b/lib/route_types.pl
index f297096633..e007de4d69 100755
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -121,7 +121,7 @@ sub codelist {
}
$str =~ s/ $//;
push @lines, $str . "\\n\" \\\n";
- push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\"";
+ push @lines, " \" > - selected route, * - FIB route, q - queued, r - rejected, b - backup\\n\\n\"";
return join("", @lines);
}
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 71d0a46449..b549c11cfc 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -85,6 +85,7 @@ ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
+ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
diff --git a/lib/routemap.c b/lib/routemap.c
index 7749ea4cc7..fb70860024 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -263,6 +263,24 @@ void route_map_no_match_tag_hook(int (*func)(
rmap_match_set_hook.no_match_tag = func;
}
+/* set sr-te color */
+void route_map_set_srte_color_hook(int (*func)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg))
+{
+ rmap_match_set_hook.set_srte_color = func;
+}
+
+/* no set sr-te color */
+void route_map_no_set_srte_color_hook(int (*func)(struct vty *vty,
+ struct route_map_index *index,
+ const char *command,
+ const char *arg))
+{
+ rmap_match_set_hook.no_set_srte_color = func;
+}
+
/* set ip nexthop */
void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
struct route_map_index *index,
@@ -353,8 +371,7 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
"%% [%s] Argument form is unsupported or malformed.\n",
frr_protonameinst);
else
- zlog_warn("Argument form is unsupported or malformed: "
- "%s %s", command, arg);
+ zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
/*
@@ -405,8 +422,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
"%% [%s] Argument form is unsupported or malformed.\n",
frr_protonameinst);
else
- zlog_warn("Argument form is unsupported or malformed: "
- "%s %s", command, arg);
+ zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
retval = CMD_WARNING_CONFIG_FAILED;
break;
case RMAP_COMPILE_SUCCESS:
@@ -441,8 +457,7 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
"%% [%s] Argument form is unsupported or malformed.\n",
frr_protonameinst);
else
- zlog_warn("Argument form is unsupported or malformed: "
- "%s %s", command, arg);
+ zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
break;
@@ -470,8 +485,7 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
"%% [%s] Argument form is unsupported or malformed.\n",
frr_protonameinst);
else
- zlog_warn("Argument form is unsupported or malformed: "
- "%s %s", command, arg);
+ zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg);
return CMD_WARNING_CONFIG_FAILED;
case RMAP_COMPILE_SUCCESS:
break;
@@ -825,9 +839,10 @@ static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
struct route_map_index *index;
struct route_map_rule *rule;
- vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s\n",
+ vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s Processed Change: %s\n",
map->name, map->applied - map->applied_clear,
- map->optimization_disabled ? "disabled" : "enabled");
+ map->optimization_disabled ? "disabled" : "enabled",
+ map->to_be_processed ? "true" : "false");
for (index = map->head; index; index = index->next) {
vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
@@ -1692,14 +1707,19 @@ route_map_get_index(struct route_map *map, const struct prefix *prefix,
* more noops, we retain this return value and
* return this eventually if there are no
* matches.
+ * If a best match route-map index already
+ * exists, do not reset the match_ret.
*/
- if (*match_ret != RMAP_NOMATCH)
+ if (!best_index && (*match_ret != RMAP_NOMATCH))
*match_ret = ret;
} else {
/*
* ret is RMAP_NOMATCH.
+ * If a best match route-map index already
+ * exists, do not reset the match_ret.
*/
- *match_ret = ret;
+ if (!best_index)
+ *match_ret = ret;
}
}
@@ -2411,6 +2431,7 @@ route_map_result_t route_map_apply(struct route_map *map,
for (; index; index = index->next) {
if (!skip_match_clause) {
+ index->applied++;
/* Apply this index. */
match_ret = route_map_apply_match(&index->match_list,
prefix, type, object);
@@ -2610,6 +2631,47 @@ static unsigned int route_map_dep_data_hash_make_key(const void *p)
return string_hash_make(dep_data->rname);
}
+DEFUN (set_srte_color,
+ set_srte_color_cmd,
+ "set sr-te color [(1-4294967295)]",
+ SET_STR
+ SRTE_STR
+ SRTE_COLOR_STR
+ "Color of the SR-TE Policies to match with\n")
+{
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+ int idx = 0;
+ char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
+ ? argv[idx]->arg
+ : NULL;
+
+ if (rmap_match_set_hook.set_srte_color)
+ return rmap_match_set_hook.set_srte_color(vty, index,
+ "sr-te color", arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_set_srte_color,
+ no_set_srte_color_cmd,
+ "no set sr-te color [(1-4294967295)]",
+ NO_STR
+ SET_STR
+ SRTE_STR
+ SRTE_COLOR_STR
+ "Color of the SR-TE Policies to match with\n")
+{
+ VTY_DECLVAR_CONTEXT(route_map_index, index);
+ int idx = 0;
+ char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
+ ? argv[idx]->arg
+ : NULL;
+
+ if (rmap_match_set_hook.no_set_srte_color)
+ return rmap_match_set_hook.no_set_srte_color(
+ vty, index, "sr-te color", arg);
+ return CMD_SUCCESS;
+}
+
static void *route_map_dep_hash_alloc(void *p)
{
char *dep_name = (char *)p;
@@ -3234,5 +3296,8 @@ void route_map_init(void)
install_element(RMAP_NODE, &routemap_optimization_cmd);
install_element(RMAP_NODE, &no_routemap_optimization_cmd);
+ install_element(RMAP_NODE, &set_srte_color_cmd);
+ install_element(RMAP_NODE, &no_set_srte_color_cmd);
+
install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
}
diff --git a/lib/routemap.h b/lib/routemap.h
index 62195b8349..64da4b87ef 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -424,6 +424,14 @@ extern void route_map_match_tag_hook(int (*func)(
extern void route_map_no_match_tag_hook(int (*func)(
struct vty *vty, struct route_map_index *index, const char *command,
const char *arg, route_map_event_t type));
+/* set sr-te color */
+extern void route_map_set_srte_color_hook(
+ int (*func)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg));
+/* no set sr-te color */
+extern void route_map_no_set_srte_color_hook(
+ int (*func)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg));
/* set ip nexthop */
extern void route_map_set_ip_nexthop_hook(
int (*func)(struct vty *vty, struct route_map_index *index,
@@ -606,6 +614,14 @@ struct route_map_match_set_hooks {
const char *command, const char *arg,
route_map_event_t type);
+ /* set sr-te color */
+ int (*set_srte_color)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
+ /* no set sr-te color */
+ int (*no_set_srte_color)(struct vty *vty, struct route_map_index *index,
+ const char *command, const char *arg);
+
/* set ip nexthop */
int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
const char *command, const char *arg);
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 2c45f09751..836be38113 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -39,7 +39,7 @@
#define ROUTE_MAP_SEQUENCE_CMD_STR \
"Sequence to insert to/delete from existing route-map entry\n"
-DEFPY_NOSH(
+DEFPY_YANG_NOSH(
route_map, route_map_cmd,
"route-map WORD$name <deny|permit>$action (1-65535)$sequence",
ROUTE_MAP_CMD_STR
@@ -70,6 +70,7 @@ DEFPY_NOSH(
VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
/* Add support for non-migrated route map users. */
+ nb_cli_pending_commit_check(vty);
rm = route_map_get(name);
action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY;
rmi = route_map_index_get(rm, action_type, sequence);
@@ -79,7 +80,7 @@ DEFPY_NOSH(
return rv;
}
-DEFPY(
+DEFPY_YANG(
no_route_map_all, no_route_map_all_cmd,
"no route-map WORD$name",
NO_STR
@@ -94,7 +95,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_route_map, no_route_map_cmd,
"no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
NO_STR
@@ -179,7 +180,7 @@ void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
vty_out(vty, "!\n");
}
-DEFPY(
+DEFPY_YANG(
match_interface, match_interface_cmd,
"match interface IFNAME",
MATCH_STR
@@ -196,7 +197,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_interface, no_match_interface_cmd,
"no match interface [IFNAME]",
NO_STR
@@ -211,9 +212,9 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ip_address, match_ip_address_cmd,
- "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ "match ip address <(1-199)|(1300-2699)|WORD>$name",
MATCH_STR
IP_STR
"Match address of route\n"
@@ -223,34 +224,15 @@ DEFPY(
{
const char *xpath = "./match-condition[condition='ipv4-address-list']";
char xpath_value[XPATH_MAXLEN + 32];
- int acln = acll ? acll : aclh;
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- if (name) {
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
- xpath);
- nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
- } else /* if (acll || aclh) */ {
- if ((acln >= 1 && acln <= 99)
- || (acln >= 1300 && acln <= 1999)) {
- snprintf(xpath_value, sizeof(xpath_value),
- "%s/access-list-num", xpath);
- } else {
- /*
- * if ((acln >= 100 && acln <= 199)
- * || (acln >= 2000 && acln <= 2699))
- */
- snprintf(xpath_value, sizeof(xpath_value),
- "%s/access-list-num-extended", xpath);
- }
- nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
- acll_str ? acll_str : aclh_str);
- }
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ip_address, no_match_ip_address_cmd,
"no match ip address [<(1-199)|(1300-2699)|WORD>]",
NO_STR
@@ -268,7 +250,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ip_address_prefix_list,
match_ip_address_prefix_list_cmd,
"match ip address prefix-list WORD$name",
@@ -288,7 +270,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
"no match ip address prefix-list [WORD]",
NO_STR
@@ -305,9 +287,9 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ip_next_hop, match_ip_next_hop_cmd,
- "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ "match ip next-hop <(1-199)|(1300-2699)|WORD>$name",
MATCH_STR
IP_STR
"Match next-hop address of route\n"
@@ -317,34 +299,15 @@ DEFPY(
{
const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
char xpath_value[XPATH_MAXLEN + 32];
- int acln = acll ? acll : aclh;
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
- if (name) {
- snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
- xpath);
- nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
- } else /* if (acll || aclh) */ {
- if ((acln >= 1 && acln <= 99)
- || (acln >= 1300 && acln <= 1999)) {
- snprintf(xpath_value, sizeof(xpath_value),
- "%s/access-list-num", xpath);
- } else {
- /*
- * if ((acln >= 100 && acln <= 199)
- * || (acln >= 2000 && acln <= 2699))
- */
- snprintf(xpath_value, sizeof(xpath_value),
- "%s/access-list-num-extended", xpath);
- }
- nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
- acll_str ? acll_str : aclh_str);
- }
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ip_next_hop, no_match_ip_next_hop_cmd,
"no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
NO_STR
@@ -362,7 +325,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ip_next_hop_prefix_list,
match_ip_next_hop_prefix_list_cmd,
"match ip next-hop prefix-list WORD$name",
@@ -383,7 +346,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ip_next_hop_prefix_list,
no_match_ip_next_hop_prefix_list_cmd,
"no match ip next-hop prefix-list [WORD]",
@@ -402,7 +365,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ip_next_hop_type, match_ip_next_hop_type_cmd,
"match ip next-hop type <blackhole>$type",
MATCH_STR
@@ -422,7 +385,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
"no match ip next-hop type [<blackhole>]",
NO_STR MATCH_STR IP_STR
@@ -437,7 +400,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ipv6_address, match_ipv6_address_cmd,
"match ipv6 address WORD$name",
MATCH_STR
@@ -455,7 +418,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ipv6_address, no_match_ipv6_address_cmd,
"no match ipv6 address [WORD]",
NO_STR
@@ -471,7 +434,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
"match ipv6 address prefix-list WORD$name",
MATCH_STR
@@ -490,7 +453,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ipv6_address_prefix_list,
no_match_ipv6_address_prefix_list_cmd,
"no match ipv6 address prefix-list [WORD]",
@@ -508,7 +471,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
"match ipv6 next-hop type <blackhole>$type",
MATCH_STR IPV6_STR
@@ -527,7 +490,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
"no match ipv6 next-hop type [<blackhole>]",
NO_STR MATCH_STR IPV6_STR
@@ -542,7 +505,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_metric, match_metric_cmd,
"match metric (0-4294967295)$metric",
MATCH_STR
@@ -559,7 +522,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_metric, no_match_metric_cmd,
"no match metric [(0-4294967295)]",
NO_STR
@@ -574,7 +537,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
match_tag, match_tag_cmd,
"match tag (1-4294967295)$tag",
MATCH_STR
@@ -591,7 +554,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_match_tag, no_match_tag_cmd,
"no match tag [(1-4294967295)]",
NO_STR
@@ -610,8 +573,6 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
int condition = yang_dnode_get_enum(dnode, "./condition");
- struct lyd_node *ln;
- const char *acl;
switch (condition) {
case 0: /* interface */
@@ -620,25 +581,14 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
break;
case 1: /* ipv4-address-list */
case 3: /* ipv4-next-hop-list */
- acl = NULL;
- if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL)
- acl = yang_dnode_get_string(ln, NULL);
- else if ((ln = yang_dnode_get(dnode, "./access-list-num"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
- else if ((ln = yang_dnode_get(dnode,
- "./access-list-num-extended"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
-
- assert(acl);
-
switch (condition) {
case 1:
- vty_out(vty, " match ip address %s\n", acl);
+ vty_out(vty, " match ip address %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
break;
case 3:
- vty_out(vty, " match ip next-hop %s\n", acl);
+ vty_out(vty, " match ip next-hop %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
break;
}
break;
@@ -697,7 +647,7 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
}
}
-DEFPY(
+DEFPY_YANG(
set_ip_nexthop, set_ip_nexthop_cmd,
"set ip next-hop A.B.C.D$addr",
SET_STR
@@ -715,7 +665,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_set_ip_nexthop, no_set_ip_nexthop_cmd,
"no set ip next-hop [A.B.C.D]",
NO_STR
@@ -731,7 +681,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd,
"set ipv6 next-hop local X:X::X:X$addr",
SET_STR
@@ -750,7 +700,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd,
"no set ipv6 next-hop local [X:X::X:X]",
NO_STR
@@ -767,7 +717,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
set_metric, set_metric_cmd,
"set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
SET_STR
@@ -813,7 +763,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_set_metric, no_set_metric_cmd,
"no set metric [(0-4294967295)]",
NO_STR
@@ -827,7 +777,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
set_tag, set_tag_cmd,
"set tag (1-4294967295)$tag",
SET_STR
@@ -844,7 +794,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_set_tag, no_set_tag_cmd,
"no set tag [(1-4294967295)]",
NO_STR
@@ -904,7 +854,7 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
}
}
-DEFPY(
+DEFPY_YANG(
rmap_onmatch_next, rmap_onmatch_next_cmd,
"on-match next",
"Exit policy on matches\n"
@@ -915,7 +865,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_rmap_onmatch_next,
no_rmap_onmatch_next_cmd,
"no on-match next",
@@ -928,7 +878,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
rmap_onmatch_goto, rmap_onmatch_goto_cmd,
"on-match goto (1-65535)$rm_num",
"Exit policy on matches\n"
@@ -941,7 +891,7 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
"no on-match goto",
NO_STR
@@ -954,13 +904,13 @@ DEFPY(
}
/* Cisco/GNU Zebra compatibility aliases */
-ALIAS(
+ALIAS_YANG(
rmap_onmatch_goto, rmap_continue_cmd,
"continue (1-65535)$rm_num",
"Continue on a different entry within the route-map\n"
"Route-map entry sequence number\n")
-ALIAS(
+ALIAS_YANG(
no_rmap_onmatch_goto, no_rmap_continue_cmd,
"no continue [(1-65535)]",
NO_STR
@@ -986,7 +936,7 @@ void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
}
}
-DEFPY(
+DEFPY_YANG(
rmap_call, rmap_call_cmd,
"call WORD$name",
"Jump to another Route-Map after match+set\n"
@@ -997,11 +947,12 @@ DEFPY(
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY(
+DEFPY_YANG(
no_rmap_call, no_rmap_call_cmd,
- "no call",
+ "no call [NAME]",
NO_STR
- "Jump to another Route-Map after match+set\n")
+ "Jump to another Route-Map after match+set\n"
+ "Target route-map name\n")
{
nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
@@ -1014,7 +965,7 @@ void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
}
-DEFPY(
+DEFPY_YANG(
rmap_description, rmap_description_cmd,
"description LINE...",
"Route-map comment\n"
@@ -1031,7 +982,7 @@ DEFPY(
return rv;
}
-DEFUN (no_rmap_description,
+DEFUN_YANG (no_rmap_description,
no_rmap_description_cmd,
"no description",
NO_STR
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index f500a6c408..967f3fd4d4 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -516,77 +516,6 @@ static int lib_route_map_entry_match_condition_interface_destroy(
}
/*
- * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num
- */
-static int lib_route_map_entry_match_condition_access_list_num_modify(
- struct nb_cb_modify_args *args)
-{
- struct routemap_hook_context *rhc;
- const char *acl;
- int condition, rv;
-
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- /* Check for hook function. */
- rv = CMD_SUCCESS;
- acl = yang_dnode_get_string(args->dnode, NULL);
- rhc = nb_running_get_entry(args->dnode, NULL, true);
- condition = yang_dnode_get_enum(args->dnode, "../condition");
- switch (condition) {
- case 1: /* ipv4-address-list */
- if (rmap_match_set_hook.match_ip_address == NULL)
- break;
- rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
- rhc->rhc_rule = "ip address";
- rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
- rv = rmap_match_set_hook.match_ip_address(
- NULL, rhc->rhc_rmi, "ip address", acl,
- RMAP_EVENT_FILTER_ADDED);
- break;
- case 3: /* ipv4-next-hop-list */
- if (rmap_match_set_hook.match_ip_next_hop == NULL)
- break;
- rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
- rhc->rhc_rule = "ip next-hop";
- rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
- rv = rmap_match_set_hook.match_ip_next_hop(
- NULL, rhc->rhc_rmi, "ip next-hop", acl,
- RMAP_EVENT_FILTER_ADDED);
- break;
- }
- if (rv != CMD_SUCCESS) {
- rhc->rhc_mhook = NULL;
- return NB_ERR_INCONSISTENCY;
- }
-
- return NB_OK;
-}
-
-static int lib_route_map_entry_match_condition_access_list_num_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_match_destroy(args);
-}
-
-/*
- * XPath:
- * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended
- */
-static int lib_route_map_entry_match_condition_access_list_num_extended_modify(
- struct nb_cb_modify_args *args)
-{
- return lib_route_map_entry_match_condition_access_list_num_modify(args);
-}
-
-static int lib_route_map_entry_match_condition_access_list_num_extended_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_match_condition_access_list_num_destroy(
- args);
-}
-
-/*
* XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
*/
static int lib_route_map_entry_match_condition_list_name_modify(
@@ -1245,20 +1174,6 @@ const struct frr_yang_module_info frr_route_map_info = {
}
},
{
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num",
- .cbs = {
- .modify = lib_route_map_entry_match_condition_access_list_num_modify,
- .destroy = lib_route_map_entry_match_condition_access_list_num_destroy,
- }
- },
- {
- .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended",
- .cbs = {
- .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify,
- .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy,
- }
- },
- {
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name",
.cbs = {
.modify = lib_route_map_entry_match_condition_list_name_modify,
diff --git a/lib/routing_nb.c b/lib/routing_nb.c
new file mode 100644
index 0000000000..0160354a7e
--- /dev/null
+++ b/lib/routing_nb.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Vmware
+ * Vishal Dhingra
+ *
+ * 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 "northbound.h"
+#include "libfrr.h"
+#include "routing_nb.h"
+
+
+
+/* clang-format off */
+const struct frr_yang_module_info frr_routing_info = {
+ .name = "frr-routing",
+ .nodes = {
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol",
+ .cbs = {
+ .create = routing_control_plane_protocols_control_plane_protocol_create,
+ .destroy = routing_control_plane_protocols_control_plane_protocol_destroy,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/lib/routing_nb.h b/lib/routing_nb.h
new file mode 100644
index 0000000000..d1b59ea29e
--- /dev/null
+++ b/lib/routing_nb.h
@@ -0,0 +1,24 @@
+#ifndef _FRR_ROUTING_NB_H_
+#define _FRR_ROUTING_NB_H_
+
+extern const struct frr_yang_module_info frr_routing_info;
+
+/* Mandatory callbacks. */
+int routing_control_plane_protocols_control_plane_protocol_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_destroy(
+ struct nb_cb_destroy_args *args);
+
+#define FRR_ROUTING_XPATH \
+ "/frr-routing:routing/control-plane-protocols/control-plane-protocol"
+
+#define FRR_ROUTING_KEY_XPATH \
+ "/frr-routing:routing/control-plane-protocols/" \
+ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']"
+/*
+ * callbacks for routing to handle configuration events
+ * based on the control plane protocol
+ */
+DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+
+#endif /* _FRR_ROUTING_NB_H_ */
diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c
new file mode 100644
index 0000000000..b789e8494e
--- /dev/null
+++ b/lib/routing_nb_config.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 Vmware
+ * Vishal Dhingra
+ *
+ * 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 "northbound.h"
+#include "libfrr.h"
+#include "vrf.h"
+#include "lib_errors.h"
+#include "routing_nb.h"
+
+
+DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+
+/*
+ * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol
+ */
+
+int routing_control_plane_protocols_control_plane_protocol_create(
+ struct nb_cb_create_args *args)
+{
+ struct vrf *vrf;
+ const char *vrfname;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (hook_call(routing_conf_event, args))
+ return NB_ERR_VALIDATION;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ vrfname = yang_dnode_get_string(args->dnode, "./vrf");
+ vrf = vrf_lookup_by_name(vrfname);
+ vrf = vrf ? vrf : vrf_get(VRF_UNKNOWN, vrfname);
+ if (!vrf) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+ "vrf creation %s failed", vrfname);
+ return NB_ERR;
+ }
+ nb_running_set_entry(args->dnode, vrf);
+ break;
+ };
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct vrf *vrf __attribute__((unused));
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrf = nb_running_unset_entry(args->dnode);
+
+ return NB_OK;
+}
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 45d9008796..21fddcd01d 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -264,8 +264,7 @@ int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr,
* up */
char buf[1][INET_ADDRSTRLEN];
zlog_info(
- "setsockopt_ipv4_multicast attempting to drop and "
- "re-add (fd %d, mcast %s, ifindex %u)",
+ "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)",
sock, inet_ntop(AF_INET, &mreqn.imr_multiaddr, buf[0],
sizeof(buf[0])),
ifindex);
@@ -306,8 +305,7 @@ int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr,
* up */
char buf[1][INET_ADDRSTRLEN];
zlog_info(
- "setsockopt_ipv4_multicast attempting to drop and "
- "re-add (fd %d, mcast %s, ifindex %u)",
+ "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)",
sock, inet_ntop(AF_INET, &mreq.imr_multiaddr, buf[0],
sizeof(buf[0])),
ifindex);
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 63d8a8c69b..d77229797c 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -27,6 +27,7 @@
#include "log.h"
#include "jhash.h"
#include "lib_errors.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union")
@@ -406,8 +407,7 @@ int sockopt_v6only(int family, int sock)
sizeof(int));
if (ret < 0) {
flog_err(EC_LIB_SOCKET,
- "can't set sockopt IPV6_V6ONLY "
- "to socket %d",
+ "can't set sockopt IPV6_V6ONLY to socket %d",
sock);
return -1;
}
@@ -666,3 +666,49 @@ void sockunion_init(union sockunion *su)
{
memset(su, 0, sizeof(union sockunion));
}
+
+printfrr_ext_autoreg_p("SU", printfrr_psu)
+static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const union sockunion *su = ptr;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
+ bool include_port = false;
+ bool endflags = false;
+ ssize_t consumed = 2;
+
+ while (!endflags) {
+ switch (fmt[consumed++]) {
+ case 'p':
+ include_port = true;
+ break;
+ default:
+ consumed--;
+ endflags = true;
+ break;
+ }
+ };
+
+ switch (sockunion_family(su)) {
+ case AF_UNSPEC:
+ bprintfrr(&fb, "(unspec)");
+ break;
+ case AF_INET:
+ inet_ntop(AF_INET, &su->sin.sin_addr, buf, bsz);
+ fb.pos += strlen(fb.buf);
+ if (include_port)
+ bprintfrr(&fb, ":%d", su->sin.sin_port);
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, bsz);
+ fb.pos += strlen(fb.buf);
+ if (include_port)
+ bprintfrr(&fb, ":%d", su->sin6.sin6_port);
+ break;
+ default:
+ bprintfrr(&fb, "(af %d)", sockunion_family(su));
+ }
+
+ fb.pos[0] = '\0';
+ return consumed;
+}
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 7091c1b5e7..72f12b77ca 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -103,6 +103,10 @@ extern union sockunion *sockunion_dup(const union sockunion *);
extern void sockunion_free(union sockunion *);
extern void sockunion_init(union sockunion *);
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pSU" (union sockunion *)
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index 66b735919b..8ffa0e9709 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -317,3 +317,13 @@ static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt,
srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz);
return 2;
}
+
+struct route_table *srcdest_srcnode_table(struct route_node *rn)
+{
+ if (rnode_is_dstnode(rn)) {
+ struct srcdest_rnode *srn = srcdest_rnode_from_rnode(rn);
+
+ return srn->src_table;
+ }
+ return NULL;
+}
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 7982260777..79afef9bb0 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -100,6 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn)
return route_table_get_info(srcdest_rnode_table(rn));
}
+extern struct route_table *srcdest_srcnode_table(struct route_node *rn);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/srte.h b/lib/srte.h
new file mode 100644
index 0000000000..d468c1cac9
--- /dev/null
+++ b/lib/srte.h
@@ -0,0 +1,56 @@
+/*
+ * SR-TE definitions
+ * Copyright 2020 NetDef Inc.
+ * Sascha Kattelmann
+ *
+ * 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 _FRR_SRTE_H
+#define _FRR_SRTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SRTE_POLICY_NAME_MAX_LENGTH 64
+
+enum zebra_sr_policy_status {
+ ZEBRA_SR_POLICY_UP = 0,
+ ZEBRA_SR_POLICY_DOWN,
+};
+
+static inline int sr_policy_compare(const struct ipaddr *a_endpoint,
+ const struct ipaddr *b_endpoint,
+ uint32_t a_color, uint32_t b_color)
+{
+ int ret;
+
+ ret = ipaddr_cmp(a_endpoint, b_endpoint);
+ if (ret < 0)
+ return -1;
+ if (ret > 0)
+ return 1;
+
+ return a_color - b_color;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_SRTE_H */
diff --git a/lib/stream.c b/lib/stream.c
index 17520f978e..768114e69b 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -55,15 +55,19 @@ DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO")
* using stream_put..._at() functions.
*/
#define STREAM_WARN_OFFSETS(S) \
- flog_warn(EC_LIB_STREAM, \
- "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
- (void *)(S), (unsigned long)(S)->size, \
- (unsigned long)(S)->getp, (unsigned long)(S)->endp)
+ do { \
+ flog_warn(EC_LIB_STREAM, \
+ "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
+ (void *)(S), (unsigned long)(S)->size, \
+ (unsigned long)(S)->getp, (unsigned long)(S)->endp); \
+ zlog_backtrace(LOG_WARNING); \
+ } while (0)
#define STREAM_VERIFY_SANE(S) \
do { \
- if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) \
+ if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) { \
STREAM_WARN_OFFSETS(S); \
+ } \
assert(GETP_VALID(S, (S)->getp)); \
assert(ENDP_VALID(S, (S)->endp)); \
} while (0)
@@ -582,6 +586,43 @@ uint32_t stream_get_ipv4(struct stream *s)
return l;
}
+bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip)
+{
+ uint16_t ipa_len;
+
+ STREAM_VERIFY_SANE(s);
+
+ /* Get address type. */
+ if (STREAM_READABLE(s) < sizeof(uint16_t)) {
+ STREAM_BOUND_WARN2(s, "get ipaddr");
+ return false;
+ }
+ ip->ipa_type = stream_getw(s);
+
+ /* Get address value. */
+ switch (ip->ipa_type) {
+ case IPADDR_V4:
+ ipa_len = IPV4_MAX_BYTELEN;
+ break;
+ case IPADDR_V6:
+ ipa_len = IPV6_MAX_BYTELEN;
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown ip address-family: %u", __func__,
+ ip->ipa_type);
+ return false;
+ }
+ if (STREAM_READABLE(s) < ipa_len) {
+ STREAM_BOUND_WARN2(s, "get ipaddr");
+ return false;
+ }
+ memcpy(&ip->ip, s->data + s->getp, ipa_len);
+ s->getp += ipa_len;
+
+ return true;
+}
+
float stream_getf(struct stream *s)
{
union {
@@ -848,6 +889,27 @@ int stream_put_in_addr(struct stream *s, const struct in_addr *addr)
return sizeof(uint32_t);
}
+bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip)
+{
+ stream_putw(s, ip->ipa_type);
+
+ switch (ip->ipa_type) {
+ case IPADDR_V4:
+ stream_put_in_addr(s, &ip->ipaddr_v4);
+ break;
+ case IPADDR_V6:
+ stream_write(s, (uint8_t *)&ip->ipaddr_v6, 16);
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unknown ip address-family: %u", __func__,
+ ip->ipa_type);
+ return false;
+ }
+
+ return true;
+}
+
/* Put in_addr at location in the stream. */
int stream_put_in_addr_at(struct stream *s, size_t putp,
const struct in_addr *addr)
diff --git a/lib/stream.h b/lib/stream.h
index 245f35db51..1250b6944d 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -189,6 +189,7 @@ extern int stream_putq(struct stream *, uint64_t);
extern int stream_putq_at(struct stream *, size_t, uint64_t);
extern int stream_put_ipv4(struct stream *, uint32_t);
extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr);
+extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip);
extern int stream_put_in_addr_at(struct stream *s, size_t putp,
const struct in_addr *addr);
extern int stream_put_in6_addr_at(struct stream *s, size_t putp,
@@ -219,6 +220,7 @@ extern uint64_t stream_getq(struct stream *);
extern uint64_t stream_getq_from(struct stream *, size_t);
bool stream_getq2(struct stream *s, uint64_t *q);
extern uint32_t stream_get_ipv4(struct stream *);
+extern bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip);
/* IEEE-754 floats */
extern float stream_getf(struct stream *);
@@ -439,6 +441,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
(P) = _pval; \
} while (0)
+#define STREAM_GET_IPADDR(S, P) \
+ do { \
+ if (!stream_get_ipaddr((S), (P))) \
+ goto stream_failure; \
+ } while (0)
+
#define STREAM_GET(P, STR, SIZE) \
do { \
if (!stream_get2((P), (STR), (SIZE))) \
diff --git a/lib/subdir.am b/lib/subdir.am
index 57b2cea832..1feaa56d13 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -108,6 +108,8 @@ lib_libfrr_la_SOURCES = \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
lib/printf/glue.c \
+ lib/routing_nb.c \
+ lib/routing_nb_config.c \
# end
nodist_lib_libfrr_la_SOURCES = \
@@ -117,13 +119,11 @@ nodist_lib_libfrr_la_SOURCES = \
yang/frr-route-types.yang.c \
yang/frr-vrf.yang.c \
yang/frr-routing.yang.c \
+ yang/frr-nexthop.yang.c \
yang/ietf/ietf-routing-types.yang.c \
yang/ietf/ietf-interfaces.yang.c \
yang/frr-module-translator.yang.c \
yang/frr-nexthop.yang.c \
- yang/frr-igmp.yang.c \
- yang/frr-pim.yang.c \
- yang/frr-pim-rp.yang.c \
# end
vtysh_scan += \
@@ -242,6 +242,7 @@ pkginclude_HEADERS += \
lib/sockunion.h \
lib/spf_backoff.h \
lib/srcdest_table.h \
+ lib/srte.h \
lib/stream.h \
lib/systemd.h \
lib/table.h \
@@ -266,6 +267,7 @@ pkginclude_HEADERS += \
lib/zlog.h \
lib/zlog_targets.h \
lib/pbr.h \
+ lib/routing_nb.h \
# end
diff --git a/lib/thread.c b/lib/thread.c
index 9b2f5661ac..19e4827283 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -305,8 +305,7 @@ DEFUN (show_thread_cpu,
filter = parse_filter(argv[idx]->arg);
if (!filter) {
vty_out(vty,
- "Invalid filter \"%s\" specified; must contain at least"
- "one of 'RWTEXB'\n",
+ "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
argv[idx]->arg);
return CMD_WARNING;
}
@@ -393,8 +392,7 @@ DEFUN (clear_thread_cpu,
filter = parse_filter(argv[idx]->arg);
if (!filter) {
vty_out(vty,
- "Invalid filter \"%s\" specified; must contain at least"
- "one of 'RWTEXB'\n",
+ "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n",
argv[idx]->arg);
return CMD_WARNING;
}
@@ -636,6 +634,36 @@ struct timeval thread_timer_remain(struct thread *thread)
return remain;
}
+static int time_hhmmss(char *buf, int buf_size, long sec)
+{
+ long hh;
+ long mm;
+ int wr;
+
+ zassert(buf_size >= 8);
+
+ hh = sec / 3600;
+ sec %= 3600;
+ mm = sec / 60;
+ sec %= 60;
+
+ wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec);
+
+ return wr != 8;
+}
+
+char *thread_timer_to_hhmmss(char *buf, int buf_size,
+ struct thread *t_timer)
+{
+ if (t_timer) {
+ time_hhmmss(buf, buf_size,
+ thread_timer_remain_second(t_timer));
+ } else {
+ snprintf(buf, buf_size, "--:--:--");
+ }
+ return buf;
+}
+
/* Get new thread. */
static struct thread *thread_get(struct thread_master *m, uint8_t type,
int (*func)(struct thread *), void *arg,
@@ -698,17 +726,16 @@ static void thread_free(struct thread_master *master, struct thread *thread)
static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
nfds_t count, const struct timeval *timer_wait)
{
- /* If timer_wait is null here, that means poll() should block
- * indefinitely,
- * unless the thread_master has overridden it by setting
+ /*
+ * If timer_wait is null here, that means poll() should block
+ * indefinitely, unless the thread_master has overridden it by setting
* ->selectpoll_timeout.
+ *
* If the value is positive, it specifies the maximum number of
- * milliseconds
- * to wait. If the timeout is -1, it specifies that we should never wait
- * and
- * always return immediately even if no event is detected. If the value
- * is
- * zero, the behavior is default. */
+ * milliseconds to wait. If the timeout is -1, it specifies that
+ * we should never wait and always return immediately even if no
+ * event is detected. If the value is zero, the behavior is default.
+ */
int timeout = -1;
/* number of file descriptors with events */
@@ -832,7 +859,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
frr_with_mutex(&m->mtx) {
if (t_ptr && *t_ptr)
- // thread is already scheduled; don't reschedule
+ /* thread is already scheduled; don't reschedule */
return NULL;
thread = thread_get(m, type, func, arg, debugargpass);
@@ -912,7 +939,7 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
frr_with_mutex(&m->mtx) {
if (t_ptr && *t_ptr)
- // thread is already scheduled; don't reschedule
+ /* thread is already scheduled; don't reschedule */
break;
thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
@@ -1019,11 +1046,12 @@ static void do_thread_cancel(struct thread_master *master)
struct cancel_req *cr;
struct listnode *ln;
for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) {
- /* If this is an event object cancellation, linear search
- * through event
- * list deleting any events which have the specified argument.
- * We also
- * need to check every thread in the ready queue. */
+ /*
+ * If this is an event object cancellation, linear search
+ * through event list deleting any events which have the
+ * specified argument. We also need to check every thread
+ * in the ready queue.
+ */
if (cr->eventobj) {
struct thread *t;
@@ -1047,11 +1075,12 @@ static void do_thread_cancel(struct thread_master *master)
continue;
}
- /* The pointer varies depending on whether the cancellation
- * request was
- * made asynchronously or not. If it was, we need to check
- * whether the
- * thread even exists anymore before cancelling it. */
+ /*
+ * The pointer varies depending on whether the cancellation
+ * request was made asynchronously or not. If it was, we
+ * need to check whether the thread even exists anymore
+ * before cancelling it.
+ */
thread = (cr->thread) ? cr->thread : *cr->threadref;
if (!thread)
@@ -1276,18 +1305,21 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
ready++;
- /* Unless someone has called thread_cancel from another pthread,
- * the only
- * thing that could have changed in m->handler.pfds while we
- * were
- * asleep is the .events field in a given pollfd. Barring
- * thread_cancel()
- * that value should be a superset of the values we have in our
- * copy, so
- * there's no need to update it. Similarily, barring deletion,
- * the fd
- * should still be a valid index into the master's pfds. */
- if (pfds[i].revents & (POLLIN | POLLHUP)) {
+ /*
+ * Unless someone has called thread_cancel from another
+ * pthread, the only thing that could have changed in
+ * m->handler.pfds while we were asleep is the .events
+ * field in a given pollfd. Barring thread_cancel() that
+ * value should be a superset of the values we have in our
+ * copy, so there's no need to update it. Similarily,
+ * barring deletion, the fd should still be a valid index
+ * into the master's pfds.
+ *
+ * We are including POLLERR here to do a READ event
+ * this is because the read should fail and the
+ * read function should handle it appropriately
+ */
+ if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
pfds[i].revents, i);
}
@@ -1399,11 +1431,10 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
*
* - If there are events pending, set the poll() timeout to zero
* - If there are no events pending, but there are timers
- * pending, set the
- * timeout to the smallest remaining time on any timer
+ * pending, set the timeout to the smallest remaining time on
+ * any timer.
* - If there are neither timers nor events pending, but there
- * are file
- * descriptors pending, block indefinitely in poll()
+ * are file descriptors pending, block indefinitely in poll()
* - If nothing is pending, it's time for the application to die
*
* In every case except the last, we need to hit poll() at least
diff --git a/lib/thread.h b/lib/thread.h
index 412a4d93bf..c22b2105cd 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -140,6 +140,8 @@ struct cpu_thread_history {
/* Thread yield time. */
#define THREAD_YIELD_TIME_SLOT 10 * 1000L /* 10ms */
+#define THREAD_TIMER_STRLEN 12
+
/* Macros. */
#define THREAD_ARG(X) ((X)->arg)
#define THREAD_FD(X) ((X)->u.fd)
@@ -228,6 +230,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
/* only for use in logging functions! */
extern pthread_key_t thread_current;
+extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
+ struct thread *t_timer);
#ifdef __cplusplus
}
diff --git a/lib/vrf.c b/lib/vrf.c
index fb64589287..2a3ce2a315 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -638,6 +638,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
ret = nb_cli_apply_changes(vty, xpath_list);
if (ret == CMD_SUCCESS) {
VTY_PUSH_XPATH(VRF_NODE, xpath_list);
+ nb_cli_pending_commit_check(vty);
vrfp = vrf_lookup_by_name(vrfname);
if (vrfp)
VTY_PUSH_CONTEXT(VRF_NODE, vrfp);
@@ -652,8 +653,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
}
int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
- ns_id_t ns_id, ns_id_t internal_ns_id,
- ns_id_t rel_def_ns_id)
+ ns_id_t ns_id, ns_id_t internal_ns_id)
{
struct ns *ns = NULL;
@@ -691,8 +691,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
return CMD_SUCCESS;
if (vty)
vty_out(vty,
- "NS %s is already configured"
- " with VRF %u(%s)\n",
+ "NS %s is already configured with VRF %u(%s)\n",
ns->name, vrf2->vrf_id, vrf2->name);
else
zlog_info("NS %s is already configured with VRF %u(%s)",
@@ -701,7 +700,6 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
}
ns = ns_get_created(ns, pathname, ns_id);
ns->internal_ns_id = internal_ns_id;
- ns->relative_default_ns = rel_def_ns_id;
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
@@ -732,7 +730,7 @@ DEFUN_NOSH(vrf_exit,
return CMD_SUCCESS;
}
-DEFUN_NOSH (vrf,
+DEFUN_YANG_NOSH (vrf,
vrf_cmd,
"vrf NAME",
"Select a VRF to configure\n"
@@ -744,7 +742,7 @@ DEFUN_NOSH (vrf,
return vrf_handler_create(vty, vrfname, NULL);
}
-DEFUN (no_vrf,
+DEFUN_YANG (no_vrf,
no_vrf_cmd,
"no vrf NAME",
NO_STR
@@ -758,10 +756,8 @@ DEFUN (no_vrf,
vrfp = vrf_lookup_by_name(vrfname);
- if (vrfp == NULL) {
- vty_out(vty, "%% VRF %s does not exist\n", vrfname);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (vrfp == NULL)
+ return CMD_SUCCESS;
if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) {
vty_out(vty, "%% Only inactive VRFs can be deleted\n");
@@ -799,9 +795,7 @@ DEFUN_NOSH (vrf_netns,
frr_with_privs(vrf_daemon_privs) {
ret = vrf_netns_handler_create(vty, vrf, pathname,
- NS_UNKNOWN,
- NS_UNKNOWN,
- NS_UNKNOWN);
+ NS_UNKNOWN, NS_UNKNOWN);
}
return ret;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index a8514d74ed..83ed16b48e 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -315,7 +315,7 @@ extern int vrf_handler_create(struct vty *vty, const char *name,
*/
extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
char *pathname, ns_id_t ext_ns_id,
- ns_id_t ns_id, ns_id_t rel_def_ns_id);
+ ns_id_t ns_id);
/* used internally to enable or disable VRF.
* Notify a change in the VRF ID of the VRF
diff --git a/lib/vty.c b/lib/vty.c
index ffef05e4dc..184c7604b8 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1244,8 +1244,7 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes)
if (vty->sb_len != TELNET_NAWS_SB_LEN)
flog_err(
EC_LIB_SYSTEM_CALL,
- "RFC 1073 violation detected: telnet NAWS option "
- "should send %d characters, but we received %lu",
+ "RFC 1073 violation detected: telnet NAWS option should send %d characters, but we received %lu",
TELNET_NAWS_SB_LEN,
(unsigned long)vty->sb_len);
else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
@@ -1261,8 +1260,7 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes)
| vty->sb_buf[4]);
#ifdef TELNET_OPTION_DEBUG
vty_out(vty,
- "TELNET NAWS window size negotiation completed: "
- "width %d, height %d\n",
+ "TELNET NAWS window size negotiation completed: width %d, height %d\n",
vty->width, vty->height);
#endif
}
@@ -2633,6 +2631,9 @@ int vty_config_node_exit(struct vty *vty)
{
vty->xpath_index = 0;
+ /* Perform pending commit if any. */
+ nb_cli_pending_commit_check(vty);
+
/* Check if there's a pending confirmed commit. */
if (vty->t_confirmed_commit_timeout) {
vty_out(vty,
diff --git a/lib/vty.h b/lib/vty.h
index 5d5676199b..623f97ab03 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -134,6 +134,14 @@ struct vty {
/* Base candidate configuration. */
struct nb_config *candidate_config_base;
+ /* Dynamic transaction information. */
+ struct timeval backoff_start;
+ size_t backoff_cmd_count;
+ struct thread *t_pending_commit;
+ char *pending_cmds_buf;
+ size_t pending_cmds_buflen;
+ size_t pending_cmds_bufpos;
+
/* Confirmed-commit timeout and rollback configuration. */
struct thread *t_confirmed_commit_timeout;
struct nb_config *confirmed_commit_rollback;
diff --git a/lib/yang.c b/lib/yang.c
index 0714ddf7bb..6ab9492d52 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -53,22 +53,30 @@ static const char *yang_module_imp_clb(const char *mod_name,
{
struct yang_module_embed *e;
- if (submod_name || submod_rev)
- return NULL;
-
for (e = embeds; e; e = e->next) {
- if (strcmp(e->mod_name, mod_name))
- continue;
- if (mod_rev && strcmp(e->mod_rev, mod_rev))
- continue;
+ if (e->sub_mod_name && submod_name) {
+ if (strcmp(e->sub_mod_name, submod_name))
+ continue;
+
+ if (submod_rev && strcmp(e->sub_mod_rev, submod_rev))
+ continue;
+ } else {
+ if (strcmp(e->mod_name, mod_name))
+ continue;
+
+ if (mod_rev && strcmp(e->mod_rev, mod_rev))
+ continue;
+ }
*format = e->format;
return e->data;
}
- flog_warn(EC_LIB_YANG_MODULE_LOAD,
- "YANG model \"%s@%s\" not embedded, trying external file",
- mod_name, mod_rev ? mod_rev : "*");
+ flog_warn(
+ EC_LIB_YANG_MODULE_LOAD,
+ "YANG model \"%s@%s\" \"%s@%s\"not embedded, trying external file",
+ mod_name, mod_rev ? mod_rev : "*",
+ submod_name ? submod_name : "*", submod_rev ? submod_rev : "*");
return NULL;
}
@@ -749,3 +757,147 @@ void yang_terminate(void)
ly_ctx_destroy(ly_native_ctx, NULL);
}
+
+const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode,
+ const char *name)
+{
+ const struct lyd_node *orig_dnode = dnode;
+
+ while (orig_dnode) {
+ switch (orig_dnode->schema->nodetype) {
+ case LYS_LIST:
+ case LYS_CONTAINER:
+ if (!strcmp(orig_dnode->schema->name, name))
+ return orig_dnode;
+ break;
+ default:
+ break;
+ }
+
+ orig_dnode = orig_dnode->parent;
+ }
+
+ return NULL;
+}
+
+/* API to check if the given node is last node in the list */
+static bool yang_is_last_list_dnode(const struct lyd_node *dnode)
+{
+ return (((dnode->next == NULL)
+ || (dnode->next
+ && (strcmp(dnode->next->schema->name, dnode->schema->name)
+ != 0)))
+ && dnode->prev
+ && ((dnode->prev == dnode)
+ || (strcmp(dnode->prev->schema->name, dnode->schema->name)
+ != 0)));
+}
+
+/* API to check if the given node is last node in the data tree level */
+static bool yang_is_last_level_dnode(const struct lyd_node *dnode)
+{
+ const struct lyd_node *parent;
+ const struct lys_node_list *snode;
+ const struct lyd_node *key_leaf;
+ uint8_t keys_size;
+
+ switch (dnode->schema->nodetype) {
+ case LYS_LIST:
+ assert(dnode->parent);
+ parent = dnode->parent;
+ snode = (struct lys_node_list *)parent->schema;
+ key_leaf = dnode->prev;
+ for (keys_size = 1; keys_size < snode->keys_size; keys_size++)
+ key_leaf = key_leaf->prev;
+ if (key_leaf->prev == dnode)
+ return true;
+ break;
+ case LYS_CONTAINER:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+const struct lyd_node *
+yang_get_subtree_with_no_sibling(const struct lyd_node *dnode)
+{
+ bool parent = true;
+ const struct lyd_node *node;
+ const struct lys_node_container *snode;
+
+ node = dnode;
+ if (node->schema->nodetype != LYS_LIST)
+ return node;
+
+ while (parent) {
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ snode = (struct lys_node_container *)node->schema;
+ if ((!snode->presence)
+ && yang_is_last_level_dnode(node)) {
+ if (node->parent
+ && (node->parent->schema->module
+ == dnode->schema->module))
+ node = node->parent;
+ else
+ parent = false;
+ } else
+ parent = false;
+ break;
+ case LYS_LIST:
+ if (yang_is_last_list_dnode(node)
+ && yang_is_last_level_dnode(node)) {
+ if (node->parent
+ && (node->parent->schema->module
+ == dnode->schema->module))
+ node = node->parent;
+ else
+ parent = false;
+ } else
+ parent = false;
+ break;
+ default:
+ parent = false;
+ break;
+ }
+ }
+ return node;
+}
+
+uint32_t yang_get_list_pos(const struct lyd_node *node)
+{
+ return lyd_list_pos(node);
+}
+
+uint32_t yang_get_list_elements_count(const struct lyd_node *node)
+{
+ unsigned int count;
+ struct lys_node *schema;
+
+ if (!node
+ || ((node->schema->nodetype != LYS_LIST)
+ && (node->schema->nodetype != LYS_LEAFLIST))) {
+ return 0;
+ }
+
+ schema = node->schema;
+ count = 0;
+ do {
+ if (node->schema == schema)
+ ++count;
+ node = node->next;
+ } while (node);
+ return count;
+}
+
+
+const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode)
+{
+ if (dnode)
+ return dnode->child;
+ return NULL;
+}
diff --git a/lib/yang.h b/lib/yang.h
index 85ef0d758c..cc048c44e8 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -34,7 +34,7 @@ extern "C" {
#endif
/* Maximum XPath length. */
-#define XPATH_MAXLEN 512
+#define XPATH_MAXLEN 1024
/* Maximum list key length. */
#define LIST_MAXKEYS 8
@@ -48,6 +48,8 @@ extern "C" {
struct yang_module_embed {
struct yang_module_embed *next;
const char *mod_name, *mod_rev;
+ const char *sub_mod_name;
+ const char *sub_mod_rev;
const char *data;
LYS_INFORMAT format;
};
@@ -551,6 +553,57 @@ extern void yang_init(bool embedded_modules);
*/
extern void yang_terminate(void);
+/*
+ * API to return the parent dnode having a given schema-node name
+ * Use case: One has to access the parent dnode's private pointer
+ * for a given child node.
+ * For that there is a need to find parent dnode first.
+ *
+ * dnode The starting node to work on
+ *
+ * name The name of container/list schema-node
+ *
+ * Returns The dnode matched with the given name
+ */
+extern const struct lyd_node *
+yang_dnode_get_parent(const struct lyd_node *dnode, const char *name);
+
+
+/*
+ * In some cases there is a need to auto delete the parent nodes
+ * if the given node is last in the list.
+ * It tries to delete all the parents in a given tree in a given module.
+ * The use case is with static routes and route maps
+ * example : ip route 1.1.1.1/32 ens33
+ * ip route 1.1.1.1/32 ens34
+ * After this no ip route 1.1.1.1/32 ens34 came, now staticd
+ * has to find out upto which level it has to delete the dnodes.
+ * For this case it has to send delete nexthop
+ * After this no ip route 1.1.1.1/32 ens33 came, now staticd has to
+ * clear nexthop, path and route nodes.
+ * The same scheme is required for routemaps also
+ * dnode The starting node to work on
+ *
+ * Returns The final parent node selected for deletion
+ */
+extern const struct lyd_node *
+yang_get_subtree_with_no_sibling(const struct lyd_node *dnode);
+
+/* To get the relative position of a node in list */
+extern uint32_t yang_get_list_pos(const struct lyd_node *node);
+
+/* To get the number of elements in a list
+ *
+ * dnode : The head of list
+ * Returns : The number of dnodes present in the list
+ */
+extern uint32_t yang_get_list_elements_count(const struct lyd_node *node);
+
+
+/* To get the immediate child of a dnode */
+const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c
index c31ba3fcc0..4c658c1bfb 100644
--- a/lib/yang_wrappers.c
+++ b/lib/yang_wrappers.c
@@ -792,6 +792,29 @@ struct yang_data *yang_data_new_empty(const char *xpath)
return yang_data_new(xpath, NULL);
}
+bool yang_dnode_get_empty(const struct lyd_node *dnode, const char *xpath_fmt,
+ ...)
+{
+ va_list ap;
+ char xpath[XPATH_MAXLEN];
+ const struct lyd_node_leaf_list *dleaf;
+
+ assert(dnode);
+
+ va_start(ap, xpath_fmt);
+ vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+ va_end(ap);
+
+ dnode = yang_dnode_get(dnode, xpath);
+ if (dnode) {
+ dleaf = (const struct lyd_node_leaf_list *)dnode;
+ if (dleaf->value_type == LY_TYPE_EMPTY)
+ return true;
+ }
+
+ return false;
+}
+
/*
* Derived type: IP prefix.
*/
@@ -1191,3 +1214,63 @@ const char *yang_nexthop_type2str(uint32_t ntype)
break;
}
}
+
+
+const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi)
+{
+ if (afi == AFI_IP && safi == SAFI_UNICAST)
+ return "frr-routing:ipv4-unicast";
+ if (afi == AFI_IP6 && safi == SAFI_UNICAST)
+ return "frr-routing:ipv6-unicast";
+ if (afi == AFI_IP && safi == SAFI_MULTICAST)
+ return "frr-routing:ipv4-multicast";
+ if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
+ return "frr-routing:ipv6-multicast";
+ if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
+ return "frr-routing:l3vpn-ipv4-unicast";
+ if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
+ return "frr-routing:l3vpn-ipv6-unicast";
+ if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ return "frr-routing:l2vpn-evpn";
+ if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+ return "frr-routing:ipv4-labeled-unicast";
+ if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+ return "frr-routing:ipv6-labeled-unicast";
+
+ return NULL;
+}
+
+void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi)
+{
+ if (strmatch(key, "frr-routing:ipv4-unicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_UNICAST;
+ } else if (strmatch(key, "frr-routing:ipv6-unicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_UNICAST;
+ } else if (strmatch(key, "frr-routing:ipv4-multicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_MULTICAST;
+ } else if (strmatch(key, "frr-routing:ipv6-multicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_MULTICAST;
+ } else if (strmatch(key, "frr-routing:l3vpn-ipv4-unicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_MPLS_VPN;
+ } else if (strmatch(key, "frr-routing:l3vpn-ipv6-unicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_MPLS_VPN;
+ } else if (strmatch(key, "frr-routing:ipv4-labeled-unicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_LABELED_UNICAST;
+ } else if (strmatch(key, "frr-routing:ipv6-labeled-unicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_LABELED_UNICAST;
+ } else if (strmatch(key, "frr-routing:l2vpn-evpn")) {
+ *afi = AFI_L2VPN;
+ *safi = SAFI_EVPN;
+ } else {
+ *afi = AFI_UNSPEC;
+ *safi = SAFI_UNSPEC;
+ }
+}
diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h
index ba2cf5139c..d781dfb1e4 100644
--- a/lib/yang_wrappers.h
+++ b/lib/yang_wrappers.h
@@ -120,6 +120,8 @@ extern void yang_get_default_string_buf(char *buf, size_t size,
/* empty */
extern struct yang_data *yang_data_new_empty(const char *xpath);
+extern bool yang_dnode_get_empty(const struct lyd_node *dnode,
+ const char *xpath_fmt, ...);
/* ip prefix */
extern void yang_str2prefix(const char *value, union prefixptr prefix);
@@ -191,6 +193,9 @@ extern struct yang_data *yang_data_new_date_and_time(const char *xpath,
/* nexthop enum2str */
extern const char *yang_nexthop_type2str(uint32_t ntype);
+const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi);
+void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/zclient.c b/lib/zclient.c
index 793864243c..808aa18bbe 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -39,6 +39,7 @@
#include "pbr.h"
#include "nexthop_group.h"
#include "lib_errors.h"
+#include "srte.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -436,7 +437,8 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
vrf_id);
/* We need router-id information. */
- zebra_message_send(zclient, ZEBRA_ROUTER_ID_ADD, vrf_id);
+ zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP,
+ vrf_id);
/* We need interface information. */
zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id);
@@ -503,7 +505,8 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
vrf_id);
/* We need router-id information. */
- zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id);
+ zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_DELETE, AFI_IP,
+ vrf_id);
zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id);
@@ -554,6 +557,18 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
}
}
+int zclient_send_router_id_update(struct zclient *zclient,
+ zebra_message_types_t type, afi_t afi,
+ vrf_id_t vrf_id)
+{
+ struct stream *s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s, type, vrf_id);
+ stream_putw(s, afi);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ return zclient_send_message(zclient);
+}
+
/* Send request to zebra daemon to start or stop RA. */
void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
struct interface *ifp, int enable,
@@ -886,9 +901,9 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp,
* Encode a single zapi nexthop
*/
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
- uint32_t api_flags)
+ uint32_t api_flags, uint32_t api_message)
{
- int ret = 0;
+ int i, ret = 0;
int nh_flags = api_nh->flags;
stream_putl(s, api_nh->vrf_id);
@@ -950,9 +965,22 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
stream_put(s, &(api_nh->rmac),
sizeof(struct ethaddr));
+ /* Color for Segment Routing TE. */
+ if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE))
+ stream_putl(s, api_nh->srte_color);
+
/* Index of backup nexthop */
- if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
- stream_putc(s, api_nh->backup_idx);
+ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ /* Validate backup count */
+ if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) {
+ ret = -1;
+ goto done;
+ }
+
+ stream_putc(s, api_nh->backup_num);
+ for (i = 0; i < api_nh->backup_num; i++)
+ stream_putc(s, api_nh->backup_idx[i]);
+ }
done:
return ret;
@@ -977,7 +1005,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
stream_putw(s, api->instance);
stream_putl(s, api->flags);
- stream_putc(s, api->message);
+ stream_putl(s, api->message);
if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) {
flog_err(EC_LIB_ZAPI_ENCODE,
@@ -1038,7 +1066,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
return -1;
}
- if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
+ if (zapi_nexthop_encode(s, api_nh, api->flags,
+ api->message)
+ != 0)
return -1;
}
}
@@ -1082,7 +1112,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
return -1;
}
- if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
+ if (zapi_nexthop_encode(s, api_nh, api->flags,
+ api->message)
+ != 0)
return -1;
}
}
@@ -1109,9 +1141,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
* Decode a single zapi nexthop object
*/
static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
- uint32_t api_flags)
+ uint32_t api_flags, uint32_t api_message)
{
- int ret = -1;
+ int i, ret = -1;
STREAM_GETL(s, api_nh->vrf_id);
STREAM_GETC(s, api_nh->type);
@@ -1162,9 +1194,20 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
STREAM_GET(&(api_nh->rmac), s,
sizeof(struct ethaddr));
+ /* Color for Segment Routing TE. */
+ if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE))
+ STREAM_GETL(s, api_nh->srte_color);
+
/* Backup nexthop index */
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
- STREAM_GETC(s, api_nh->backup_idx);
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
+ STREAM_GETC(s, api_nh->backup_num);
+
+ if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS)
+ return -1;
+
+ for (i = 0; i < api_nh->backup_num; i++)
+ STREAM_GETC(s, api_nh->backup_idx[i]);
+ }
/* Success */
ret = 0;
@@ -1192,7 +1235,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
STREAM_GETW(s, api->instance);
STREAM_GETL(s, api->flags);
- STREAM_GETC(s, api->message);
+ STREAM_GETL(s, api->message);
STREAM_GETC(s, api->safi);
if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) {
flog_err(EC_LIB_ZAPI_ENCODE,
@@ -1267,7 +1310,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
for (i = 0; i < api->nexthop_num; i++) {
api_nh = &api->nexthops[i];
- if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
+ if (zapi_nexthop_decode(s, api_nh, api->flags,
+ api->message)
+ != 0)
return -1;
}
}
@@ -1285,7 +1330,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
for (i = 0; i < api->backup_nexthop_num; i++) {
api_nh = &api->backup_nexthops[i];
- if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
+ if (zapi_nexthop_decode(s, api_nh, api->flags,
+ api->message)
+ != 0)
return -1;
}
}
@@ -1472,6 +1519,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
n->vrf_id = znh->vrf_id;
n->ifindex = znh->ifindex;
n->gate = znh->gate;
+ n->srte_color = znh->srte_color;
/*
* This function currently handles labels
@@ -1483,7 +1531,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
- n->backup_idx = znh->backup_idx;
+ n->backup_num = znh->backup_num;
+ memcpy(n->backup_idx, znh->backup_idx, n->backup_num);
}
return n;
@@ -1519,8 +1568,12 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
}
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (nh->backup_num > NEXTHOP_MAX_BACKUPS)
+ return -1;
+
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
- znh->backup_idx = nh->backup_idx;
+ znh->backup_num = nh->backup_num;
+ memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num);
}
return 0;
@@ -1584,6 +1637,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
memset(nhr, 0, sizeof(*nhr));
+ STREAM_GETL(s, nhr->message);
STREAM_GETW(s, nhr->prefix.family);
STREAM_GETC(s, nhr->prefix.prefixlen);
switch (nhr->prefix.family) {
@@ -1596,6 +1650,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
default:
break;
}
+ if (CHECK_FLAG(nhr->message, ZAPI_MESSAGE_SRTE))
+ STREAM_GETL(s, nhr->srte_color);
STREAM_GETC(s, nhr->type);
STREAM_GETW(s, nhr->instance);
@@ -1604,7 +1660,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
STREAM_GETC(s, nhr->nexthop_num);
for (i = 0; i < nhr->nexthop_num; i++) {
- if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0) != 0)
+ if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0, 0) != 0)
return -1;
}
@@ -1924,8 +1980,7 @@ static int link_params_set_value(struct stream *s, struct if_link_params *iflp)
if (i < bwclassnum)
flog_err(
EC_LIB_ZAPI_MISSMATCH,
- "%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
- " - outdated library?",
+ "%s: received %d > %d (MAX_CLASS_TYPE) bw entries - outdated library?",
__func__, bwclassnum, MAX_CLASS_TYPE);
}
STREAM_GETL(s, iflp->admin_grp);
@@ -2801,6 +2856,92 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
return zclient_send_message(zclient);
}
+int zebra_send_sr_policy(struct zclient *zclient, int cmd,
+ struct zapi_sr_policy *zp)
+{
+ if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0)
+ return -1;
+ return zclient_send_message(zclient);
+}
+
+int zapi_sr_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp)
+{
+ struct zapi_srte_tunnel *zt = &zp->segment_list;
+
+ stream_reset(s);
+
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+ stream_putl(s, zp->color);
+ stream_put_ipaddr(s, &zp->endpoint);
+ stream_write(s, &zp->name, SRTE_POLICY_NAME_MAX_LENGTH);
+
+ stream_putc(s, zt->type);
+ stream_putl(s, zt->local_label);
+
+ if (zt->label_num > MPLS_MAX_LABELS) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: label %u: can't encode %u labels (maximum is %u)",
+ __func__, zt->local_label, zt->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
+ }
+ stream_putw(s, zt->label_num);
+
+ for (int i = 0; i < zt->label_num; i++)
+ stream_putl(s, zt->labels[i]);
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp)
+{
+ memset(zp, 0, sizeof(*zp));
+
+ struct zapi_srte_tunnel *zt = &zp->segment_list;
+
+ STREAM_GETL(s, zp->color);
+ STREAM_GET_IPADDR(s, &zp->endpoint);
+ STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH);
+
+ /* segment list of active candidate path */
+ STREAM_GETC(s, zt->type);
+ STREAM_GETL(s, zt->local_label);
+ STREAM_GETW(s, zt->label_num);
+ if (zt->label_num > MPLS_MAX_LABELS) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: label %u: can't decode %u labels (maximum is %u)",
+ __func__, zt->local_label, zt->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
+ }
+ for (int i = 0; i < zt->label_num; i++)
+ STREAM_GETL(s, zt->labels[i]);
+
+ return 0;
+
+stream_failure:
+ return -1;
+}
+
+int zapi_sr_policy_notify_status_decode(struct stream *s,
+ struct zapi_sr_policy *zp)
+{
+ memset(zp, 0, sizeof(*zp));
+
+ STREAM_GETL(s, zp->color);
+ STREAM_GET_IPADDR(s, &zp->endpoint);
+ STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH);
+ STREAM_GETL(s, zp->status);
+
+ return 0;
+
+stream_failure:
+ return -1;
+}
+
int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
struct zapi_labels *zl)
{
@@ -2840,7 +2981,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
for (int i = 0; i < zl->nexthop_num; i++) {
znh = &zl->nexthops[i];
- if (zapi_nexthop_encode(s, znh, 0) < 0)
+ if (zapi_nexthop_encode(s, znh, 0, 0) < 0)
return -1;
}
@@ -2859,7 +3000,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
for (int i = 0; i < zl->backup_nexthop_num; i++) {
znh = &zl->backup_nexthops[i];
- if (zapi_nexthop_encode(s, znh, 0) < 0)
+ if (zapi_nexthop_encode(s, znh, 0, 0) < 0)
return -1;
}
@@ -2935,7 +3076,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
for (int i = 0; i < zl->nexthop_num; i++) {
znh = &zl->nexthops[i];
- if (zapi_nexthop_decode(s, znh, 0) < 0)
+ if (zapi_nexthop_decode(s, znh, 0, 0) < 0)
return -1;
}
@@ -2956,7 +3097,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
for (int i = 0; i < zl->backup_nexthop_num; i++) {
znh = &zl->backup_nexthops[i];
- if (zapi_nexthop_decode(s, znh, 0) < 0)
+ if (zapi_nexthop_decode(s, znh, 0, 0) < 0)
return -1;
}
}
@@ -3499,6 +3640,16 @@ static int zclient_read(struct thread *thread)
(*zclient->local_es_del)(command, zclient, length,
vrf_id);
break;
+ case ZEBRA_LOCAL_ES_EVI_ADD:
+ if (zclient->local_es_evi_add)
+ (*zclient->local_es_evi_add)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_LOCAL_ES_EVI_DEL:
+ if (zclient->local_es_evi_del)
+ (*zclient->local_es_evi_del)(command, zclient, length,
+ vrf_id);
+ break;
case ZEBRA_VNI_ADD:
if (zclient->local_vni_add)
(*zclient->local_vni_add)(command, zclient, length,
@@ -3613,6 +3764,10 @@ static int zclient_read(struct thread *thread)
(*zclient->opaque_unregister_handler)(command, zclient,
length, vrf_id);
break;
+ case ZEBRA_SR_POLICY_NOTIFY_STATUS:
+ if (zclient->sr_policy_notify_status)
+ (*zclient->sr_policy_notify_status)(command, zclient,
+ length, vrf_id);
default:
break;
}
@@ -3798,3 +3953,23 @@ int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
stream_failure:
return 0;
}
+
+int zclient_send_neigh_discovery_req(struct zclient *zclient,
+ const struct interface *ifp,
+ const struct prefix *p)
+{
+ struct stream *s;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf_id);
+ stream_putl(s, ifp->ifindex);
+
+ stream_putc(s, p->family);
+ stream_putc(s, p->prefixlen);
+ stream_put(s, &p->u.prefix, prefix_blen(p));
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ return zclient_send_message(zclient);
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index 3ded2f55d7..dab384d5ec 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -37,6 +37,7 @@
#include "pw.h"
#include "mlag.h"
+#include "srte.h"
#ifdef __cplusplus
extern "C" {
@@ -89,6 +90,8 @@ enum zserv_client_capabilities {
/* Macro to check if there GR enabled. */
#define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES)
+#define ZEBRA_SR_POLICY_NAME_MAX_LENGTH 100
+
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
@@ -143,6 +146,9 @@ typedef enum {
ZEBRA_MPLS_LABELS_ADD,
ZEBRA_MPLS_LABELS_DELETE,
ZEBRA_MPLS_LABELS_REPLACE,
+ ZEBRA_SR_POLICY_SET,
+ ZEBRA_SR_POLICY_DELETE,
+ ZEBRA_SR_POLICY_NOTIFY_STATUS,
ZEBRA_IPMR_ROUTE_STATS,
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_LABEL_MANAGER_CONNECT_ASYNC,
@@ -157,6 +163,10 @@ typedef enum {
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_LOCAL_ES_ADD,
ZEBRA_LOCAL_ES_DEL,
+ ZEBRA_REMOTE_ES_VTEP_ADD,
+ ZEBRA_REMOTE_ES_VTEP_DEL,
+ ZEBRA_LOCAL_ES_EVI_ADD,
+ ZEBRA_LOCAL_ES_EVI_DEL,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
ZEBRA_L3VNI_ADD,
@@ -204,6 +214,7 @@ typedef enum {
ZEBRA_OPAQUE_MESSAGE,
ZEBRA_OPAQUE_REGISTER,
ZEBRA_OPAQUE_UNREGISTER,
+ ZEBRA_NEIGH_DISCOVER,
} zebra_message_types_t;
enum zebra_error_types {
@@ -321,6 +332,8 @@ struct zclient {
int (*fec_update)(int, struct zclient *, uint16_t);
int (*local_es_add)(ZAPI_CALLBACK_ARGS);
int (*local_es_del)(ZAPI_CALLBACK_ARGS);
+ int (*local_es_evi_add)(ZAPI_CALLBACK_ARGS);
+ int (*local_es_evi_del)(ZAPI_CALLBACK_ARGS);
int (*local_vni_add)(ZAPI_CALLBACK_ARGS);
int (*local_vni_del)(ZAPI_CALLBACK_ARGS);
int (*local_l3vni_add)(ZAPI_CALLBACK_ARGS);
@@ -345,6 +358,7 @@ struct zclient {
int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS);
int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
+ int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
};
/* Zebra API message flag. */
@@ -362,7 +376,8 @@ struct zclient {
* the table being used is not in the VRF. You must pass the
* default vrf, else this will be ignored.
*/
-#define ZAPI_MESSAGE_TABLEID 0x80
+#define ZAPI_MESSAGE_TABLEID 0x0080
+#define ZAPI_MESSAGE_SRTE 0x0100
#define ZSERV_VERSION 6
/* Zserv protocol message header */
@@ -394,8 +409,12 @@ struct zapi_nexthop {
uint32_t weight;
- /* Index of backup nexthop */
- uint8_t backup_idx;
+ /* Backup nexthops, for IP-FRR, TI-LFA, etc */
+ uint8_t backup_num;
+ uint8_t backup_idx[NEXTHOP_MAX_BACKUPS];
+
+ /* SR-TE color. */
+ uint32_t srte_color;
};
/*
@@ -458,7 +477,7 @@ struct zapi_route {
#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40
/* The older XXX_MESSAGE flags live here */
- uint8_t message;
+ uint32_t message;
/*
* This is an enum but we are going to treat it as a uint8_t
@@ -487,6 +506,9 @@ struct zapi_route {
vrf_id_t vrf_id;
uint32_t tableid;
+
+ /* SR-TE color (used for nexthop updates only). */
+ uint32_t srte_color;
};
struct zapi_labels {
@@ -509,6 +531,21 @@ struct zapi_labels {
struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
};
+struct zapi_srte_tunnel {
+ enum lsp_types_t type;
+ mpls_label_t local_label;
+ uint8_t label_num;
+ mpls_label_t labels[MPLS_MAX_LABELS];
+};
+
+struct zapi_sr_policy {
+ uint32_t color;
+ struct ipaddr endpoint;
+ char name[SRTE_POLICY_NAME_MAX_LENGTH];
+ struct zapi_srte_tunnel segment_list;
+ int status;
+};
+
struct zapi_pw {
char ifname[IF_NAMESIZE];
ifindex_t ifindex;
@@ -600,6 +637,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */
#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */
#define ZEBRA_MACIP_TYPE_SVI_IP 0x10 /* SVI MAC-IP */
+#define ZEBRA_MACIP_TYPE_PROXY_ADVERT 0x20 /* Not locally active */
+#define ZEBRA_MACIP_TYPE_SYNC_PATH 0x40 /* sync path */
+/* XXX - flags is an u8; that needs to be changed to u32 if you need
+ * to allocate past 0x80
+ */
enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
@@ -647,6 +689,9 @@ extern void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id,
extern void zclient_send_reg_requests(struct zclient *, vrf_id_t);
extern void zclient_send_dereg_requests(struct zclient *, vrf_id_t);
+extern int zclient_send_router_id_update(struct zclient *zclient,
+ zebra_message_types_t type, afi_t afi,
+ vrf_id_t vrf_id);
extern void zclient_send_interface_radv_req(struct zclient *zclient,
vrf_id_t vrf_id,
@@ -763,6 +808,14 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
uint32_t end);
+extern int zebra_send_sr_policy(struct zclient *zclient, int cmd,
+ struct zapi_sr_policy *zp);
+extern int zapi_sr_policy_encode(struct stream *s, int cmd,
+ struct zapi_sr_policy *zp);
+extern int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp);
+extern int zapi_sr_policy_notify_status_decode(struct stream *s,
+ struct zapi_sr_policy *zp);
+
extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
struct zapi_labels *zl);
extern int zapi_labels_encode(struct stream *s, int cmd,
@@ -779,7 +832,7 @@ extern int zclient_send_rnh(struct zclient *zclient, int command,
const struct prefix *p, bool exact_match,
vrf_id_t vrf_id);
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
- uint32_t api_flags);
+ uint32_t api_flags, uint32_t api_message);
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
extern int zapi_route_decode(struct stream *, struct zapi_route *);
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
@@ -904,6 +957,10 @@ enum zapi_opaque_registry {
*/
extern int zclient_send_hello(struct zclient *client);
+extern int zclient_send_neigh_discovery_req(struct zclient *zclient,
+ const struct interface *ifp,
+ const struct prefix *p);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/zlog.c b/lib/zlog.c
index 45726755f8..8dfd20371b 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -246,10 +246,10 @@ void zlog_tls_buffer_init(void)
fchown(mmfd, zlog_uid, zlog_gid);
#ifdef HAVE_POSIX_FALLOCATE
- if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) < 0) {
-#else
- if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) {
+ if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) != 0)
+ /* note next statement is under above if() */
#endif
+ if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) {
zlog_err("failed to allocate thread log buffer \"%s\": %s",
mmpath, strerror(errno));
goto out_anon_unlink;