summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/atomlist.c4
-rw-r--r--lib/atomlist.h2
-rw-r--r--lib/bfd.c63
-rw-r--r--lib/bfd.h53
-rw-r--r--lib/buffer.c2
-rw-r--r--lib/command.c116
-rw-r--r--lib/command.h14
-rw-r--r--lib/command_graph.c157
-rw-r--r--lib/command_graph.h11
-rw-r--r--lib/command_match.h2
-rw-r--r--lib/command_parse.y16
-rw-r--r--lib/db.c2
-rw-r--r--lib/distribute.h2
-rw-r--r--lib/elf_py.c3
-rw-r--r--lib/ferr.c8
-rw-r--r--lib/ferr.h2
-rw-r--r--lib/filter.c126
-rw-r--r--lib/filter.h16
-rw-r--r--lib/filter_cli.c41
-rw-r--r--lib/frr_zmq.c2
-rw-r--r--lib/frrcu.h2
-rw-r--r--lib/frrlua.c67
-rw-r--r--lib/frrlua.h8
-rw-r--r--lib/frrscript.c92
-rw-r--r--lib/frrscript.h53
-rw-r--r--lib/grammar_sandbox.c2
-rw-r--r--lib/graph.c2
-rw-r--r--lib/hash.h2
-rw-r--r--lib/hook.h2
-rw-r--r--lib/if.c554
-rw-r--r--lib/if.h81
-rw-r--r--lib/json.c24
-rw-r--r--lib/json.h48
-rw-r--r--lib/lib_errors.c8
-rw-r--r--lib/libfrr.c59
-rw-r--r--lib/libfrr.h10
-rw-r--r--lib/libospf.h2
-rw-r--r--lib/link_state.c238
-rw-r--r--lib/link_state.h10
-rw-r--r--lib/log.c5
-rw-r--r--lib/log.h10
-rw-r--r--lib/log_vty.c60
-rw-r--r--lib/netns_linux.c2
-rw-r--r--lib/network.h36
-rw-r--r--lib/nexthop_group.c24
-rw-r--r--lib/northbound.c3
-rw-r--r--lib/northbound.h7
-rw-r--r--lib/northbound_cli.c8
-rw-r--r--lib/northbound_cli.h3
-rw-r--r--lib/northbound_confd.c91
-rw-r--r--lib/pbr.h9
-rw-r--r--lib/plist.c27
-rw-r--r--lib/prefix.c2
-rw-r--r--lib/resolver.c192
-rw-r--r--lib/resolver.h8
-rw-r--r--lib/route_opaque.h6
-rw-r--r--lib/routemap.c124
-rw-r--r--lib/routemap.h109
-rw-r--r--lib/routemap_cli.c195
-rw-r--r--lib/routemap_northbound.c20
-rw-r--r--lib/sbuf.h2
-rw-r--r--lib/sigevent.c38
-rw-r--r--lib/sigevent.h16
-rw-r--r--lib/skiplist.c2
-rw-r--r--lib/skiplist.h2
-rw-r--r--lib/snmp.c4
-rw-r--r--lib/sockopt.c4
-rw-r--r--lib/srv6.c96
-rw-r--r--lib/srv6.h3
-rw-r--r--lib/subdir.am3
-rw-r--r--lib/table.c2
-rw-r--r--lib/thread.c73
-rw-r--r--lib/thread.h45
-rw-r--r--lib/typerb.c10
-rw-r--r--lib/typerb.h8
-rw-r--r--lib/typesafe.c41
-rw-r--r--lib/typesafe.h110
-rw-r--r--lib/vector.c44
-rw-r--r--lib/vector.h8
-rw-r--r--lib/vrf.c202
-rw-r--r--lib/vrf.h17
-rw-r--r--lib/vty.c309
-rw-r--r--lib/vty.h18
-rw-r--r--lib/vxlan.h2
-rw-r--r--lib/xref.c4
-rw-r--r--lib/xref.h13
-rw-r--r--lib/yang.h2
-rw-r--r--lib/zclient.c414
-rw-r--r--lib/zclient.h92
-rw-r--r--lib/zebra.h3
-rw-r--r--lib/zlog.c97
-rw-r--r--lib/zlog.h22
92 files changed, 2590 insertions, 1963 deletions
diff --git a/lib/atomlist.c b/lib/atomlist.c
index 8169ba9eb4..b7c9516a00 100644
--- a/lib/atomlist.c
+++ b/lib/atomlist.c
@@ -18,6 +18,8 @@
#include "config.h"
#endif
+#include <assert.h>
+
#include "atomlist.h"
void atomlist_add_head(struct atomlist_head *h, struct atomlist_item *item)
@@ -121,7 +123,7 @@ static void atomlist_del_core(struct atomlist_head *h,
memory_order_consume);
/* track the beginning of a chain of deleted items
- * this is neccessary to make this lock-free; we can
+ * this is necessary to make this lock-free; we can
* complete deletions started by other threads.
*/
if (!atomptr_l(prevval)) {
diff --git a/lib/atomlist.h b/lib/atomlist.h
index c795128a34..b0c4da4baa 100644
--- a/lib/atomlist.h
+++ b/lib/atomlist.h
@@ -100,7 +100,7 @@ static inline bool atomptr_u(atomptr_t val)
/* single-linked list, unsorted/arbitrary.
* can be used as queue with add_tail / pop
*
- * all operations are lock-free, but not neccessarily wait-free. this means
+ * all operations are lock-free, but not necessarily wait-free. this means
* that there is no state where the system as a whole stops making process,
* but it *is* possible that a *particular* thread is delayed by some time.
*
diff --git a/lib/bfd.c b/lib/bfd.c
index ea363b7ca4..f3fc473773 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -143,8 +143,8 @@ static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
if (ifp == NULL) {
if (bsglobal.debugging)
zlog_debug(
- "zebra_interface_bfd_read: Can't find interface by ifindex: %d ",
- ifindex);
+ "%s: Can't find interface by ifindex: %d ",
+ __func__, ifindex);
return NULL;
}
}
@@ -203,7 +203,7 @@ static void bfd_last_update(time_t last_update, char *buf, size_t len)
struct tm tm;
struct timeval tv;
- /* If no BFD satatus update has ever been received, print `never'. */
+ /* If no BFD status update has ever been received, print `never'. */
if (last_update == 0) {
snprintf(buf, len, "never");
return;
@@ -251,8 +251,8 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
if (ret == ZCLIENT_SEND_FAILURE) {
if (bsglobal.debugging)
zlog_debug(
- "bfd_client_sendmsg %ld: zclient_send_message() failed",
- (long)getpid());
+ "%s: %ld: zclient_send_message() failed",
+ __func__, (long)getpid());
return;
}
@@ -552,7 +552,8 @@ static bool bfd_sess_address_changed(const struct bfd_session_params *bsp,
}
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
- struct in_addr *src, struct in_addr *dst)
+ const struct in_addr *src,
+ const struct in_addr *dst)
{
if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
(struct in6_addr *)dst))
@@ -576,10 +577,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
}
void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
- struct in6_addr *src, struct in6_addr *dst)
+ const struct in6_addr *src,
+ const struct in6_addr *dst)
{
- if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
- (struct in6_addr *)dst))
+ if (!bfd_sess_address_changed(bsp, AF_INET6, src, dst))
return;
/* If already installed, remove the old setting. */
@@ -645,32 +646,16 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
bsp->args.vrf_id = vrf_id;
}
-void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl)
-{
- assert(min_ttl != 0);
-
- if (bsp->args.ttl == ((BFD_SINGLE_HOP_TTL + 1) - min_ttl))
- return;
-
- /* If already installed, remove the old setting. */
- _bfd_sess_remove(bsp);
-
- /* Invert TTL value: protocol expects number of hops. */
- min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl;
- bsp->args.ttl = min_ttl;
- bsp->args.mhop = (min_ttl > 1);
-}
-
-void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl)
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops)
{
- if (bsp->args.ttl == min_ttl)
+ if (bsp->args.ttl == hops)
return;
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
- bsp->args.ttl = min_ttl;
- bsp->args.mhop = (min_ttl > 1);
+ bsp->args.ttl = hops;
+ bsp->args.mhop = (hops > 1);
}
@@ -705,11 +690,6 @@ enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp)
return bsp->bss.state;
}
-uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp)
-{
- return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl);
-}
-
uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp)
{
return bsp->args.ttl;
@@ -821,10 +801,13 @@ void bfd_sess_show(struct vty *vty, struct json_object *json,
*
* Use this as `zclient` `bfd_dest_replay` callback.
*/
-static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
+int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS)
{
struct bfd_session_params *bsp;
+ if (!zclient->bfd_integration)
+ return 0;
+
/* Do nothing when shutting down. */
if (bsglobal.shutting_down)
return 0;
@@ -855,7 +838,7 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
+int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
{
struct bfd_session_params *bsp, *bspn;
size_t sessions_updated = 0;
@@ -868,6 +851,9 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
struct prefix sp;
char ifstr[128], cbitstr[32];
+ if (!zclient->bfd_integration)
+ return 0;
+
/* Do nothing when shutting down. */
if (bsglobal.shutting_down)
return 0;
@@ -969,9 +955,8 @@ void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm)
bsglobal.zc = zc;
bsglobal.tm = tm;
- /* Install our callbacks. */
- zc->interface_bfd_dest_update = zclient_bfd_session_update;
- zc->bfd_dest_replay = zclient_bfd_session_reply;
+ /* Enable BFD callbacks. */
+ zc->bfd_integration = true;
/* Send the client registration */
bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
diff --git a/lib/bfd.h b/lib/bfd.h
index 6c0d1c177e..05b45a1c34 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -124,7 +124,8 @@ void bfd_sess_free(struct bfd_session_params **bsp);
* \param dst remote address (mandatory).
*/
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
- struct in_addr *src, struct in_addr *dst);
+ const struct in_addr *src,
+ const struct in_addr *dst);
/**
* Set the local and peer address of the BFD session.
@@ -138,7 +139,8 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
* \param dst remote address (mandatory).
*/
void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
- struct in6_addr *src, struct in6_addr *dst);
+ const struct in6_addr *src,
+ const struct in6_addr *dst);
/**
* Configure the BFD session interface.
@@ -179,39 +181,14 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id);
* Configure the BFD session single/multi hop setting.
*
* NOTE:
- * If the TTL changed the session is removed and must be installed again
- * with `bfd_sess_install`.
+ * If the number of hops is changed the session is removed and must be
+ * installed again with `bfd_sess_install`.
*
* \param bsp BFD session parameters.
- * \param min_ttl minimum TTL value expected (255 for single hop, 254 for
- * multi hop with single hop, 253 for multi hop with two hops
- * and so on). See `BFD_SINGLE_HOP_TTL` and
- * `BFD_MULTI_HOP_MIN_TTL` for defaults.
- *
- * To simplify things if your protocol only knows the amount of hops it is
- * better to use `bfd_sess_set_hops` instead.
+ * \param hops maximum amount of hops expected (1 for single hop, 2 or
+ * more for multi hop).
*/
-void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl);
-
-/** To use single hop the minimum TTL must be set to this. */
-#define BFD_SINGLE_HOP_TTL 255
-/** To use multi hop the minimum TTL must be set to this or less. */
-#define BFD_MULTI_HOP_MIN_TTL 254
-
-/**
- * This function is the inverted version of `bfd_sess_set_minimum_ttl`.
- * Instead of receiving the minimum expected TTL, it receives the amount of
- * hops the protocol will jump.
- *
- * NOTE:
- * If the TTL changed the session is removed and must be installed again
- * with `bfd_sess_install`.
- *
- * \param bsp BFD session parameters.
- * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or
- * more for multi hop).
- */
-void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl);
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops);
/**
* Configure the BFD session to set the Control Plane Independent bit.
@@ -276,17 +253,7 @@ void bfd_sess_uninstall(struct bfd_session_params *bsp);
enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp);
/**
- * Get BFD session minimum TTL configured value.
- *
- * \param bsp session parameters.
- *
- * \returns configured minimum TTL.
- */
-uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp);
-
-/**
- * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the
- * way to the peer.
+ * Get BFD session amount of hops configured value.
*
* \param bsp session parameters.
*
diff --git a/lib/buffer.c b/lib/buffer.c
index 41b1adc9fc..e976fecc1f 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -59,7 +59,7 @@ struct buffer_data {
/* It should always be true that: 0 <= sp <= cp <= size */
/* Default buffer size (used if none specified). It is rounded up to the
- next page boundery. */
+ next page boundary. */
#define BUFFER_SIZE_DEFAULT 4096
#define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D))
diff --git a/lib/command.c b/lib/command.c
index 53aa064705..9cf93ea192 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -86,6 +86,9 @@ vector cmdvec = NULL;
/* Host information structure. */
struct host host;
+/* for vtysh, put together CLI trees only when switching into node */
+static bool defer_cli_tree;
+
/*
* Returns host.name if any, otherwise
* it returns the system hostname.
@@ -142,31 +145,6 @@ static struct cmd_node config_node = {
.node_exit = vty_config_node_exit,
};
-static bool vty_check_node_for_xpath_decrement(enum node_type target_node,
- enum node_type node)
-{
- /* bgp afi-safi (`address-family <afi> <safi>`) node
- * does not increment xpath_index.
- * In order to use (`router bgp`) BGP_NODE's xpath as a base,
- * retain xpath_index as 1 upon exiting from
- * afi-safi node.
- */
-
- if (target_node == BGP_NODE
- && (node == BGP_IPV4_NODE || node == BGP_IPV6_NODE
- || node == BGP_IPV4M_NODE || node == BGP_IPV6M_NODE
- || node == BGP_VPNV4_NODE || node == BGP_VPNV6_NODE
- || node == BGP_EVPN_NODE || node == BGP_IPV4L_NODE
- || node == BGP_IPV6L_NODE || node == BGP_FLOWSPECV4_NODE
- || node == BGP_FLOWSPECV6_NODE))
- return false;
-
- if (target_node == INTERFACE_NODE && node == LINK_PARAMS_NODE)
- return false;
-
- return true;
-}
-
/* This is called from main when a daemon is invoked with -v or --version. */
void print_version(const char *progname)
{
@@ -285,6 +263,11 @@ const char *cmd_prompt(enum node_type node)
return cnode->prompt;
}
+void cmd_defer_tree(bool val)
+{
+ defer_cli_tree = val;
+}
+
/* Install a command into a node. */
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
{
@@ -319,20 +302,50 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd)
assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
+ if (cnode->graph_built || !defer_cli_tree) {
+ struct graph *graph = graph_new();
+ struct cmd_token *token =
+ cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ graph_new_node(graph, token,
+ (void (*)(void *)) & cmd_token_del);
+
+ cmd_graph_parse(graph, cmd);
+ cmd_graph_names(graph);
+ cmd_graph_merge(cnode->cmdgraph, graph, +1);
+ graph_delete_graph(graph);
+
+ cnode->graph_built = true;
+ }
+
+ vector_set(cnode->cmd_vector, (void *)cmd);
+
+ if (ntype == VIEW_NODE)
+ _install_element(ENABLE_NODE, cmd);
+}
+
+static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
+{
+ struct cmd_node *cnode = arg;
+ const struct cmd_element *cmd = hb->data;
struct graph *graph = graph_new();
struct cmd_token *token =
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
cmd_graph_parse(graph, cmd);
cmd_graph_names(graph);
cmd_graph_merge(cnode->cmdgraph, graph, +1);
graph_delete_graph(graph);
+}
- vector_set(cnode->cmd_vector, (void *)cmd);
+void cmd_finalize_node(struct cmd_node *cnode)
+{
+ if (cnode->graph_built)
+ return;
- if (ntype == VIEW_NODE)
- _install_element(ENABLE_NODE, cmd);
+ hash_iterate(cnode->cmd_hash, cmd_finalize_iter, cnode);
+ cnode->graph_built = true;
}
void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
@@ -368,15 +381,18 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
vector_unset_value(cnode->cmd_vector, (void *)cmd);
- struct graph *graph = graph_new();
- struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
- graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
+ if (cnode->graph_built) {
+ struct graph *graph = graph_new();
+ struct cmd_token *token =
+ cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ graph_new_node(graph, token,
+ (void (*)(void *)) & cmd_token_del);
- cmd_graph_parse(graph, cmd);
- cmd_graph_names(graph);
- cmd_graph_merge(cnode->cmdgraph, graph, -1);
- graph_delete_graph(graph);
+ cmd_graph_parse(graph, cmd);
+ cmd_graph_names(graph);
+ cmd_graph_merge(cnode->cmdgraph, graph, -1);
+ graph_delete_graph(graph);
+ }
if (ntype == VIEW_NODE)
uninstall_element(ENABLE_NODE, cmd);
@@ -503,6 +519,8 @@ static int config_write_host(struct vty *vty)
static struct graph *cmd_node_graph(vector v, enum node_type ntype)
{
struct cmd_node *cnode = vector_slot(v, ntype);
+
+ cmd_finalize_node(cnode);
return cnode->cmdgraph;
}
@@ -879,13 +897,15 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
* a match before calling node_exit handlers below
*/
for (i = 0; i < up_level; i++) {
+ struct cmd_node *cnode;
+
if (node <= CONFIG_NODE)
return CMD_NO_LEVEL_UP;
+ cnode = vector_slot(cmdvec, node);
node = node_parent(node);
- if (xpath_index > 0
- && vty_check_node_for_xpath_decrement(node, vty->node))
+ if (xpath_index > 0 && !cnode->no_xpath)
xpath_index--;
}
@@ -1019,12 +1039,13 @@ int cmd_execute_command(vector vline, struct vty *vty,
/* This assumes all nodes above CONFIG_NODE are childs of
* CONFIG_NODE */
while (vty->node > CONFIG_NODE) {
+ struct cmd_node *cnode = vector_slot(cmdvec, try_node);
+
try_node = node_parent(try_node);
vty->node = try_node;
- if (vty->xpath_index > 0
- && vty_check_node_for_xpath_decrement(try_node,
- onode))
+ if (vty->xpath_index > 0 && !cnode->no_xpath)
vty->xpath_index--;
+
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
vty, cmd, 0);
if (ret == CMD_SUCCESS || ret == CMD_WARNING
@@ -1343,8 +1364,7 @@ void cmd_exit(struct vty *vty)
}
if (cnode->parent_node)
vty->node = cnode->parent_node;
- if (vty->xpath_index > 0
- && vty_check_node_for_xpath_decrement(vty->node, cnode->node))
+ if (vty->xpath_index > 0 && !cnode->no_xpath)
vty->xpath_index--;
}
@@ -1506,9 +1526,10 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
{
struct cmd_node *node = vector_slot(cmdvec, vty->node);
- if (do_permute)
+ if (do_permute) {
+ cmd_finalize_node(node);
permute(vector_slot(node->cmdgraph->nodes, 0), vty);
- else {
+ } else {
/* loop over all commands at this node */
const struct cmd_element *element = NULL;
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
@@ -1551,7 +1572,10 @@ DEFUN_HIDDEN(show_cli_graph,
"Dump current command space as DOT graph\n")
{
struct cmd_node *cn = vector_slot(cmdvec, vty->node);
- char *dot = cmd_graph_dump_dot(cn->cmdgraph);
+ char *dot;
+
+ cmd_finalize_node(cn);
+ dot = cmd_graph_dump_dot(cn->cmdgraph);
vty_out(vty, "%s\n", dot);
XFREE(MTYPE_TMP, dot);
diff --git a/lib/command.h b/lib/command.h
index 8a7c9a2048..c888356d61 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -210,6 +210,12 @@ struct cmd_node {
/* Hashed index of command node list, for de-dupping primarily */
struct hash *cmd_hash;
+
+ /* set as soon as any command is in cmdgraph */
+ bool graph_built;
+
+ /* don't decrement vty->xpath_index on leaving this node */
+ bool no_xpath;
};
/* Return value of the commands. */
@@ -234,7 +240,7 @@ struct cmd_node {
/* Argc max counts. */
#define CMD_ARGC_MAX 256
-/* Turn off these macros when uisng cpp with extract.pl */
+/* Turn off these macros when using cpp with extract.pl */
#ifndef VTYSH_EXTRACT_PL
/* helper defines for end-user DEFUN* macros */
@@ -526,6 +532,12 @@ extern void _install_element(enum node_type, const struct cmd_element *);
* deprecated/hidden) are not reversed. */
extern void uninstall_element(enum node_type, const struct cmd_element *);
+/* construct CLI tree only when entering nodes */
+extern void cmd_defer_tree(bool val);
+
+/* finish CLI tree for node when above is true (noop otherwise) */
+extern void cmd_finalize_node(struct cmd_node *node);
+
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
string with a space between each element (allocated using
XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 15c8302e63..09d802e796 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -77,16 +77,17 @@ struct cmd_token *cmd_token_dup(struct cmd_token *token)
return copy;
}
-void cmd_token_varname_set(struct cmd_token *token, const char *varname)
+static void cmd_token_varname_do(struct cmd_token *token, const char *varname,
+ uint8_t varname_src)
{
- XFREE(MTYPE_CMD_VAR, token->varname);
- if (!varname) {
- token->varname = NULL;
+ if (token->varname_src >= varname_src)
return;
- }
+
+ XFREE(MTYPE_CMD_VAR, token->varname);
size_t len = strlen(varname), i;
token->varname = XMALLOC(MTYPE_CMD_VAR, len + 1);
+ token->varname_src = varname_src;
for (i = 0; i < len; i++)
switch (varname[i]) {
@@ -102,6 +103,80 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname)
token->varname[len] = '\0';
}
+void cmd_token_varname_set(struct cmd_token *token, const char *varname)
+{
+ if (varname) {
+ cmd_token_varname_do(token, varname, VARNAME_EXPLICIT);
+ return;
+ }
+ if (token->type == VARIABLE_TKN) {
+ if (strcmp(token->text, "WORD") && strcmp(token->text, "NAME"))
+ cmd_token_varname_do(token, token->text, VARNAME_TEXT);
+ }
+}
+
+static void cmd_token_varname_fork(struct graph_node *node,
+ struct cmd_token *prevtoken)
+{
+ for (size_t i = 0; i < vector_active(node->to); i++) {
+ struct graph_node *next = vector_slot(node->to, i);
+ struct cmd_token *nexttoken = next->data;
+
+ if (nexttoken->type == FORK_TKN) {
+ cmd_token_varname_fork(next, prevtoken);
+ continue;
+ }
+ if (nexttoken->varname)
+ continue;
+ if (!IS_VARYING_TOKEN(nexttoken->type))
+ continue;
+
+ cmd_token_varname_do(nexttoken, prevtoken->text, VARNAME_TEXT);
+ }
+}
+
+void cmd_token_varname_join(struct graph_node *join, const char *varname)
+{
+ if (!varname)
+ return;
+
+ for (size_t i = 0; i < vector_active(join->from); i++) {
+ struct graph_node *prev = vector_slot(join->from, i);
+ struct cmd_token *token = prev->data;
+
+ if (token->type == JOIN_TKN)
+ cmd_token_varname_join(prev, varname);
+ else if (token->type < SPECIAL_TKN)
+ cmd_token_varname_do(token, varname, VARNAME_EXPLICIT);
+ }
+}
+
+void cmd_token_varname_seqappend(struct graph_node *node)
+{
+ struct graph_node *prevnode = node;
+ struct cmd_token *token = node->data;
+ struct cmd_token *prevtoken;
+
+ if (token->type == WORD_TKN)
+ return;
+
+ do {
+ if (vector_active(prevnode->from) != 1)
+ return;
+
+ prevnode = vector_slot(prevnode->from, 0);
+ prevtoken = prevnode->data;
+ } while (prevtoken->type == FORK_TKN);
+
+ if (prevtoken->type != WORD_TKN)
+ return;
+
+ if (token->type == FORK_TKN)
+ cmd_token_varname_fork(node, prevtoken);
+ else
+ cmd_token_varname_do(token, prevtoken->text, VARNAME_TEXT);
+}
+
static bool cmd_nodes_link(struct graph_node *from, struct graph_node *to)
{
for (size_t i = 0; i < vector_active(from->to); i++)
@@ -357,72 +432,6 @@ void cmd_graph_merge(struct graph *old, struct graph *new, int direction)
vector_slot(new->nodes, 0), direction);
}
-static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
- const char *prevname)
-{
- size_t i;
- struct cmd_token *tok = gn->data, *jointok;
- struct graph_node *stop = cmd_loopstop(gn);
-
- switch (tok->type) {
- case WORD_TKN:
- prevname = tok->text;
- break;
-
- case VARIABLE_TKN:
- if (!tok->varname && strcmp(tok->text, "WORD")
- && strcmp(tok->text, "NAME"))
- cmd_token_varname_set(tok, tok->text);
- /* fallthrough */
- case RANGE_TKN:
- case IPV4_TKN:
- case IPV4_PREFIX_TKN:
- case IPV6_TKN:
- case IPV6_PREFIX_TKN:
- case MAC_TKN:
- case MAC_PREFIX_TKN:
- if (!tok->varname && prevname)
- cmd_token_varname_set(tok, prevname);
- prevname = NULL;
- break;
-
- case START_TKN:
- case JOIN_TKN:
- case NEG_ONLY_TKN:
- /* "<foo|bar> WORD" -> word is not "bar" or "foo" */
- prevname = NULL;
- break;
-
- case FORK_TKN:
- /* apply "<A.B.C.D|X:X::X:X>$name" */
- jointok = tok->forkjoin->data;
- if (!jointok->varname)
- break;
- for (i = 0; i < vector_active(tok->forkjoin->from); i++) {
- struct graph_node *tail =
- vector_slot(tok->forkjoin->from, i);
- struct cmd_token *tailtok = tail->data;
- if (tail == gn || tailtok->varname)
- continue;
- cmd_token_varname_set(tailtok, jointok->varname);
- }
- break;
-
- case END_TKN:
- return;
- }
-
- for (i = 0; i < vector_active(gn->to); i++) {
- struct graph_node *next = vector_slot(gn->to, i);
- if (next == stop || next == join)
- continue;
- cmd_node_names(next, join, prevname);
- }
-
- if (tok->type == FORK_TKN && tok->forkjoin != join)
- cmd_node_names(tok->forkjoin, join, NULL);
-}
-
void cmd_graph_names(struct graph *graph)
{
struct graph_node *start;
@@ -451,12 +460,10 @@ void cmd_graph_names(struct graph *graph)
struct cmd_token *tok1 = next1->data;
/* the other one needs to be "no" (only one will match here) */
if ((tok0->type == WORD_TKN && !strcmp(tok0->text, "no")))
- cmd_token_varname_set(tok0, "no");
+ cmd_token_varname_do(tok0, "no", VARNAME_AUTO);
if ((tok1->type == WORD_TKN && !strcmp(tok1->text, "no")))
- cmd_token_varname_set(tok1, "no");
+ cmd_token_varname_do(tok1, "no", VARNAME_AUTO);
} while (0);
-
- cmd_node_names(start, NULL, NULL);
}
#ifndef BUILDING_CLIPPY
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 86157f872e..ed4da6aa4c 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -79,11 +79,20 @@ enum { CMD_ATTR_NORMAL,
CMD_ATTR_YANG,
};
+enum varname_src {
+ VARNAME_NONE = 0,
+ VARNAME_AUTO,
+ VARNAME_VAR,
+ VARNAME_TEXT,
+ VARNAME_EXPLICIT,
+};
+
/* Command token struct. */
struct cmd_token {
enum cmd_token_type type; // token type
uint8_t attr; // token attributes
bool allowrepeat; // matcher allowed to match token repetitively?
+ uint8_t varname_src;
uint32_t refcnt;
char *text; // token text
@@ -119,6 +128,8 @@ extern struct cmd_token *cmd_token_new(enum cmd_token_type, uint8_t attr,
extern struct cmd_token *cmd_token_dup(struct cmd_token *);
extern void cmd_token_del(struct cmd_token *);
extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
+extern void cmd_token_varname_seqappend(struct graph_node *n);
+extern void cmd_token_varname_join(struct graph_node *n, const char *varname);
extern void cmd_graph_parse(struct graph *graph, const struct cmd_element *cmd);
extern void cmd_graph_names(struct graph *graph);
diff --git a/lib/command_match.h b/lib/command_match.h
index fcb333120f..0488cc1a1f 100644
--- a/lib/command_match.h
+++ b/lib/command_match.h
@@ -68,7 +68,7 @@ enum match_type {
* @param[in] vline vectorized input string
* @param[out] argv pointer to argument list if successful match, NULL
* otherwise. The elements of this list are pointers to struct cmd_token
- * and represent the sequence of tokens matched by the inpu. The ->arg
+ * and represent the sequence of tokens matched by the input. The ->arg
* field of each token points to a copy of the input matched on it. These
* may be safely deleted or modified.
* @param[out] element pointer to matched cmd_element if successful match,
diff --git a/lib/command_parse.y b/lib/command_parse.y
index 3e2cdc79af..35c119691b 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -217,10 +217,12 @@ cmd_token:
{
if ((ctx->currnode = graph_add_edge (ctx->currnode, $1)) != $1)
graph_delete_node (ctx->graph, $1);
+ cmd_token_varname_seqappend($1);
}
| selector
{
graph_add_edge (ctx->currnode, $1.start);
+ cmd_token_varname_seqappend($1.start);
ctx->currnode = $1.end;
}
;
@@ -295,9 +297,8 @@ placeholder_token_real:
placeholder_token:
placeholder_token_real varname_token
{
- struct cmd_token *token = $$->data;
$$ = $1;
- cmd_token_varname_set (token, $2);
+ cmd_token_varname_set ($$->data, $2);
XFREE (MTYPE_LEX, $2);
};
@@ -306,7 +307,7 @@ placeholder_token:
selector: '<' selector_seq_seq '>' varname_token
{
$$ = $2;
- cmd_token_varname_set ($2.end->data, $4);
+ cmd_token_varname_join ($2.end, $4);
XFREE (MTYPE_LEX, $4);
};
@@ -338,11 +339,11 @@ selector: '{' selector_seq_seq '}' varname_token
* 1) this allows "at least 1 of" semantics, which are otherwise impossible
* 2) this would add a start->end->start loop in the graph that the current
* loop-avoidal fails to handle
- * just use [{a|b}] if neccessary, that will work perfectly fine, and reason
+ * just use [{a|b}] if necessary, that will work perfectly fine, and reason
* #1 is good enough to keep it this way. */
loopcheck(ctx, &$$);
- cmd_token_varname_set ($2.end->data, $4);
+ cmd_token_varname_join ($2.end, $4);
XFREE (MTYPE_LEX, $4);
};
@@ -359,6 +360,7 @@ selector_token_seq:
selector_token_seq selector_token
{
graph_add_edge ($1.end, $2.start);
+ cmd_token_varname_seqappend($2.start);
$$.start = $1.start;
$$.end = $2.end;
}
@@ -370,7 +372,7 @@ selector: '[' selector_seq_seq ']' varname_token
{
$$ = $2;
graph_add_edge ($$.start, $$.end);
- cmd_token_varname_set ($2.end->data, $4);
+ cmd_token_varname_join ($2.end, $4);
XFREE (MTYPE_LEX, $4);
}
;
@@ -383,7 +385,7 @@ selector: EXCL_BRACKET selector_seq_seq ']' varname_token
$$ = $2;
graph_add_edge ($$.start, neg_only);
graph_add_edge (neg_only, $$.end);
- cmd_token_varname_set ($2.end->data, $4);
+ cmd_token_varname_join ($2.end, $4);
XFREE (MTYPE_LEX, $4);
}
;
diff --git a/lib/db.c b/lib/db.c
index 32ba83b656..b4286b8d2c 100644
--- a/lib/db.c
+++ b/lib/db.c
@@ -60,7 +60,7 @@ int db_init(const char *path_fmt, ...)
(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), NULL)
!= SQLITE_OK) {
if (dbp == NULL) {
- zlog_warn("%s: failed to open dabatase '%s'", __func__,
+ zlog_warn("%s: failed to open database '%s'", __func__,
path);
return -1;
}
diff --git a/lib/distribute.h b/lib/distribute.h
index 83682dea6a..6b3226e8b4 100644
--- a/lib/distribute.h
+++ b/lib/distribute.h
@@ -29,7 +29,7 @@
extern "C" {
#endif
-/* Disctirubte list types. */
+/* Distribute list types. */
enum distribute_type {
DISTRIBUTE_V4_IN,
DISTRIBUTE_V6_IN,
diff --git a/lib/elf_py.c b/lib/elf_py.c
index 1c306893ad..f230add695 100644
--- a/lib/elf_py.c
+++ b/lib/elf_py.c
@@ -636,6 +636,9 @@ static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx)
Elf_Scn *scn = elf_getscn(ef->elf, i);
GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr);
+ /* virtual address is kinda meaningless for TLS sections */
+ if (shdr->sh_flags & SHF_TLS)
+ continue;
if (addr < shdr->sh_addr ||
addr >= shdr->sh_addr + shdr->sh_size)
continue;
diff --git a/lib/ferr.c b/lib/ferr.c
index 513ef5ebec..e5b6d7552d 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -157,13 +157,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
}
}
- if (json) {
- const char *str = json_object_to_json_string_ext(
- top, JSON_C_TO_STRING_PRETTY);
- vty_out(vty, "%s\n", str);
- json_object_free(top);
- }
-
+ vty_json(vty, top);
list_delete(&errlist);
}
diff --git a/lib/ferr.h b/lib/ferr.h
index 4e95431cea..c27601f66c 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -34,7 +34,7 @@ extern "C" {
/* return type when this error indication stuff is used.
*
* guaranteed to have boolean evaluation to "false" when OK, "true" when error
- * (i.e. can be changed to pointer in the future if neccessary)
+ * (i.e. can be changed to pointer in the future if necessary)
*
* For checking, always use "if (value)", nothing else.
* Do _NOT_ use any integer constant (!= 0), or sign check (< 0).
diff --git a/lib/filter.c b/lib/filter.c
index 744ea9c480..fc4b578e77 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -192,7 +192,7 @@ void access_list_delete(struct access_list *access)
access_list_free(access);
}
-/* Insert new access list to list of access_list. Each acceess_list
+/* Insert new access list to list of access_list. Each access_list
is sorted by the name. */
static struct access_list *access_list_insert(afi_t afi, const char *name)
{
@@ -387,7 +387,7 @@ void access_list_filter_add(struct access_list *access,
struct filter *replace;
struct filter *point;
- /* Automatic asignment of seq no. */
+ /* Automatic assignment of seq no. */
if (filter->seq == -1)
filter->seq = filter_new_seq_get(access);
@@ -558,18 +558,12 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi,
json_rule);
else {
if (json) {
- char buf[BUFSIZ];
-
- json_object_string_add(
- json_rule, "address",
- inet_ntop(AF_INET,
- &filter->addr, buf,
- sizeof(buf)));
- json_object_string_add(
- json_rule, "mask",
- inet_ntop(AF_INET,
- &filter->addr_mask,
- buf, sizeof(buf)));
+ json_object_string_addf(
+ json_rule, "address", "%pI4",
+ &filter->addr);
+ json_object_string_addf(
+ json_rule, "mask", "%pI4",
+ &filter->addr_mask);
} else {
if (filter->addr_mask.s_addr
== 0xffffffff)
@@ -589,14 +583,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi,
}
}
- if (json) {
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
-
- return CMD_SUCCESS;
+ return vty_json(vty, json);
}
/* show MAC access list - this only has MAC filters for now*/
@@ -612,7 +599,7 @@ DEFUN (show_mac_access_list,
DEFUN (show_mac_access_list_name,
show_mac_access_list_name_cmd,
- "show mac access-list WORD",
+ "show mac access-list ACCESSLIST_MAC_NAME",
SHOW_STR
"mac access lists\n"
"List mac access lists\n"
@@ -635,15 +622,11 @@ DEFUN (show_ip_access_list,
DEFUN (show_ip_access_list_name,
show_ip_access_list_name_cmd,
- "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> [json]",
+ "show ip access-list ACCESSLIST4_NAME [json]",
SHOW_STR
IP_STR
"List IP access lists\n"
- "IP standard access list\n"
- "IP extended access list\n"
- "IP standard access list (expanded range)\n"
- "IP extended access list (expanded range)\n"
- "IP zebra access-list\n"
+ "IP access-list name\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
@@ -665,11 +648,11 @@ DEFUN (show_ipv6_access_list,
DEFUN (show_ipv6_access_list_name,
show_ipv6_access_list_name_cmd,
- "show ipv6 access-list WORD [json]",
+ "show ipv6 access-list ACCESSLIST6_NAME [json]",
SHOW_STR
IPV6_STR
"List IPv6 access lists\n"
- "IPv6 zebra access-list\n"
+ "IPv6 access-list name\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
@@ -685,21 +668,15 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter,
filter = &mfilter->u.cfilter;
if (json) {
- char buf[BUFSIZ];
-
json_object_boolean_add(json, "extended", !!filter->extended);
- json_object_string_add(
- json, "sourceAddress",
- inet_ntop(AF_INET, &filter->addr, buf, sizeof(buf)));
- json_object_string_add(json, "sourceMask",
- inet_ntop(AF_INET, &filter->addr_mask,
- buf, sizeof(buf)));
- json_object_string_add(
- json, "destinationAddress",
- inet_ntop(AF_INET, &filter->mask, buf, sizeof(buf)));
- json_object_string_add(json, "destinationMask",
- inet_ntop(AF_INET, &filter->mask_mask,
- buf, sizeof(buf)));
+ json_object_string_addf(json, "sourceAddress", "%pI4",
+ &filter->addr);
+ json_object_string_addf(json, "sourceMask", "%pI4",
+ &filter->addr_mask);
+ json_object_string_addf(json, "destinationAddress", "%pI4",
+ &filter->mask);
+ json_object_string_addf(json, "destinationMask", "%pI4",
+ &filter->mask_mask);
} else {
vty_out(vty, " ip");
if (filter->addr_mask.s_addr == 0xffffffff)
@@ -734,16 +711,13 @@ static void config_write_access_zebra(struct vty *vty, struct filter *mfilter,
p = &filter->prefix;
if (json) {
- json_object_string_add(json, "prefix",
- prefix2str(p, buf, sizeof(buf)));
+ json_object_string_addf(json, "prefix", "%pFX", p);
json_object_boolean_add(json, "exact-match", !!filter->exact);
} else {
if (p->prefixlen == 0 && !filter->exact)
vty_out(vty, " any");
else if (p->family == AF_INET6 || p->family == AF_INET)
- vty_out(vty, " %s/%d%s",
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
- p->prefixlen,
+ vty_out(vty, " %pFX%s", p,
filter->exact ? " exact-match" : "");
else if (p->family == AF_ETHERNET) {
if (p->prefixlen == 0)
@@ -843,12 +817,62 @@ static void access_list_init_ipv4(void)
install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
}
+static void access_list_autocomplete_afi(afi_t afi, vector comps,
+ struct cmd_token *token)
+{
+ struct access_list *access;
+ struct access_list *next;
+ struct access_master *master;
+
+ master = access_master_get(afi);
+ if (master == NULL)
+ return;
+
+ for (access = master->str.head; access; access = next) {
+ next = access->next;
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, access->name));
+ }
+}
+
static struct cmd_node access_ipv6_node = {
.name = "ipv6 access list",
.node = ACCESS_IPV6_NODE,
.prompt = "",
};
+static void access_list_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP, comps, token);
+ access_list_autocomplete_afi(AFI_IP6, comps, token);
+ access_list_autocomplete_afi(AFI_L2VPN, comps, token);
+}
+
+static void access_list4_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP, comps, token);
+}
+
+static void access_list6_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP6, comps, token);
+}
+
+static void access_list_mac_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_L2VPN, comps, token);
+}
+
+static const struct cmd_variable_handler access_list_handlers[] = {
+ {.tokenname = "ACCESSLIST_NAME",
+ .completions = access_list_autocomplete},
+ {.tokenname = "ACCESSLIST4_NAME",
+ .completions = access_list4_autocomplete},
+ {.tokenname = "ACCESSLIST6_NAME",
+ .completions = access_list6_autocomplete},
+ {.tokenname = "ACCESSLIST_MAC_NAME",
+ .completions = access_list_mac_autocomplete},
+ {.completions = NULL}};
+
static void access_list_reset_ipv6(void)
{
struct access_list *access;
@@ -878,6 +902,8 @@ static void access_list_init_ipv6(void)
void access_list_init(void)
{
+ cmd_variable_handler_register(access_list_handlers);
+
access_list_init_ipv4();
access_list_init_ipv6();
access_list_init_mac();
diff --git a/lib/filter.h b/lib/filter.h
index d1956ec019..b378288c58 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -234,15 +234,19 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda);
struct lyd_node;
struct vty;
-extern int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
-extern void access_list_show(struct vty *vty, struct lyd_node *dnode,
+extern int access_list_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
+extern void access_list_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
-extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+extern void access_list_remark_show(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
-extern int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
-extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
+extern int prefix_list_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
+extern void prefix_list_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
-extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+extern void prefix_list_remark_show(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
void filter_cli_init(void);
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 45c7544a3b..fb40c527dd 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -36,10 +36,7 @@
#endif /* VTYSH_EXTRACT_PL */
#define ACCESS_LIST_STR "Access list entry\n"
-#define ACCESS_LIST_LEG_STR "IP standard access list\n"
-#define ACCESS_LIST_ELEG_STR "IP extended access list\n"
-#define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n"
-#define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
+#define ACCESS_LIST_ZEBRA_STR "Access list name\n"
#define ACCESS_LIST_SEQ_STR \
"Sequence number of an entry\n" \
"Sequence number\n"
@@ -137,7 +134,7 @@ DEFPY_YANG(
access_list_std, access_list_std_cmd,
"access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
ACCESS_LIST_STR
- ACCESS_LIST_LEG_STR
+ ACCESS_LIST_ZEBRA_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
@@ -214,7 +211,7 @@ DEFPY_YANG(
"no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
NO_STR
ACCESS_LIST_STR
- ACCESS_LIST_LEG_STR
+ ACCESS_LIST_ZEBRA_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
@@ -258,7 +255,7 @@ DEFPY_YANG(
access_list_ext, access_list_ext_cmd,
"access-list WORD$name [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
- ACCESS_LIST_ELEG_STR
+ ACCESS_LIST_ZEBRA_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"IPv4 address\n"
@@ -377,7 +374,7 @@ DEFPY_YANG(
"no access-list WORD$name [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
ACCESS_LIST_STR
- ACCESS_LIST_ELEG_STR
+ ACCESS_LIST_ZEBRA_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"Any Internet Protocol\n"
@@ -825,7 +822,7 @@ DEFPY_YANG(
ALIAS(
no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd,
- "no ipv6 access-list WORD$name remark LINE...",
+ "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...",
NO_STR
IPV6_STR
ACCESS_LIST_STR
@@ -835,7 +832,7 @@ ALIAS(
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 access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
MAC_STR
ACCESS_LIST_STR
ACCESS_LIST_ZEBRA_STR
@@ -901,7 +898,7 @@ DEFPY_YANG(
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$mac|any>",
+ "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -941,7 +938,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_mac_access_list_all, no_mac_access_list_all_cmd,
- "no mac access-list WORD$name",
+ "no mac access-list ACCESSLIST_MAC_NAME$name",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -958,7 +955,7 @@ DEFPY_YANG(
DEFPY_YANG(
mac_access_list_remark, mac_access_list_remark_cmd,
- "mac access-list WORD$name remark LINE...",
+ "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
MAC_STR
ACCESS_LIST_STR
ACCESS_LIST_ZEBRA_STR
@@ -983,7 +980,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_mac_access_list_remark, no_mac_access_list_remark_cmd,
- "no mac access-list WORD$name remark",
+ "no mac access-list ACCESSLIST_MAC_NAME$name remark",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -1007,7 +1004,7 @@ DEFPY_YANG(
ALIAS(
no_mac_access_list_remark, no_mac_access_list_remark_line_cmd,
- "no mac access-list WORD$name remark LINE...",
+ "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -1015,7 +1012,8 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
-int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+int access_list_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2)
{
uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
@@ -1023,7 +1021,7 @@ int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
return seq1 - seq2;
}
-void access_list_show(struct vty *vty, struct lyd_node *dnode,
+void access_list_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
int type = yang_dnode_get_enum(dnode, "../type");
@@ -1137,7 +1135,7 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, "\n");
}
-void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+void access_list_remark_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
int type = yang_dnode_get_enum(dnode, "../type");
@@ -1658,7 +1656,8 @@ ALIAS(
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
-int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+int prefix_list_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2)
{
uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
@@ -1666,7 +1665,7 @@ int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
return seq1 - seq2;
}
-void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
+void prefix_list_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
int type = yang_dnode_get_enum(dnode, "../type");
@@ -1725,7 +1724,7 @@ void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, "\n");
}
-void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+void prefix_list_remark_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
int type = yang_dnode_get_enum(dnode, "../type");
diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c
index 4e947a8a84..e572558de1 100644
--- a/lib/frr_zmq.c
+++ b/lib/frr_zmq.c
@@ -19,7 +19,7 @@
/*
* IF YOU MODIFY THIS FILE PLEASE RUN `make check` and ensure that
- * the test_zmq.c unit test is still working. There are dependancies
+ * the test_zmq.c unit test is still working. There are dependencies
* between the two that are extremely fragile. My understanding
* is that there is specialized ownership of the cb pointer based
* upon what is happening. Those assumptions are supposed to be
diff --git a/lib/frrcu.h b/lib/frrcu.h
index 3808259040..ae840926b5 100644
--- a/lib/frrcu.h
+++ b/lib/frrcu.h
@@ -17,6 +17,8 @@
#ifndef _FRRCU_H
#define _FRRCU_H
+#include <assert.h>
+
#include "memory.h"
#include "atomlist.h"
diff --git a/lib/frrlua.c b/lib/frrlua.c
index 00491568f6..535649eff2 100644
--- a/lib/frrlua.c
+++ b/lib/frrlua.c
@@ -223,6 +223,21 @@ void *lua_toin6addr(lua_State *L, int idx)
return in6addr;
}
+void lua_pushipaddr(lua_State *L, const struct ipaddr *addr)
+{
+ if (IS_IPADDR_V4(addr))
+ lua_pushinaddr(L, &addr->ipaddr_v4);
+ else
+ lua_pushin6addr(L, &addr->ipaddr_v6);
+}
+
+void lua_pushethaddr(lua_State *L, const struct ethaddr *addr)
+{
+ lua_newtable(L);
+ lua_pushinteger(L, *(addr->octet));
+ lua_setfield(L, -2, "octet");
+}
+
void lua_pushsockunion(lua_State *L, const union sockunion *su)
{
char buf[SU_ADDRSTRLEN];
@@ -297,6 +312,58 @@ void *lua_tointegerp(lua_State *L, int idx)
return num;
}
+void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop)
+{
+ lua_newtable(L);
+ lua_pushinteger(L, nexthop->vrf_id);
+ lua_setfield(L, -2, "vrf_id");
+ lua_pushinteger(L, nexthop->ifindex);
+ lua_setfield(L, -2, "ifindex");
+ lua_pushinteger(L, nexthop->type);
+ lua_setfield(L, -2, "type");
+ lua_pushinteger(L, nexthop->flags);
+ lua_setfield(L, -2, "flags");
+ if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
+ lua_pushinteger(L, nexthop->bh_type);
+ lua_setfield(L, -2, "bh_type");
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV4) {
+ lua_pushinaddr(L, &nexthop->gate.ipv4);
+ lua_setfield(L, -2, "gate");
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV6) {
+ lua_pushin6addr(L, &nexthop->gate.ipv6);
+ lua_setfield(L, -2, "gate");
+ }
+ lua_pushinteger(L, nexthop->nh_label_type);
+ lua_setfield(L, -2, "nh_label_type");
+ lua_pushinteger(L, nexthop->weight);
+ lua_setfield(L, -2, "weight");
+ lua_pushinteger(L, nexthop->backup_num);
+ lua_setfield(L, -2, "backup_num");
+ lua_pushinteger(L, *(nexthop->backup_idx));
+ lua_setfield(L, -2, "backup_idx");
+ if (nexthop->nh_encap_type == NET_VXLAN) {
+ lua_pushinteger(L, nexthop->nh_encap.vni);
+ lua_setfield(L, -2, "vni");
+ }
+ lua_pushinteger(L, nexthop->nh_encap_type);
+ lua_setfield(L, -2, "nh_encap_type");
+ lua_pushinteger(L, nexthop->srte_color);
+ lua_setfield(L, -2, "srte_color");
+}
+
+void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng)
+{
+ lua_newtable(L);
+ struct nexthop *nexthop;
+ int i = 0;
+
+ for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
+ lua_pushnexthop(L, nexthop);
+ lua_seti(L, -2, i);
+ i++;
+ }
+}
+
void lua_decode_stringp(lua_State *L, int idx, char *str)
{
strlcpy(str, lua_tostring(L, idx), strlen(str) + 1);
diff --git a/lib/frrlua.h b/lib/frrlua.h
index 3e16c82e22..a82009a779 100644
--- a/lib/frrlua.h
+++ b/lib/frrlua.h
@@ -100,6 +100,10 @@ void lua_pushin6addr(lua_State *L, const struct in6_addr *addr);
void lua_decode_in6addr(lua_State *L, int idx, struct in6_addr *addr);
+void lua_pushipaddr(lua_State *L, const struct ipaddr *addr);
+
+void lua_pushethaddr(lua_State *L, const struct ethaddr *addr);
+
/*
* Converts the Lua value at idx to an in6_addr.
*
@@ -138,6 +142,10 @@ void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su);
*/
void *lua_tosockunion(lua_State *L, int idx);
+void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng);
+
+void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop);
+
/*
* Converts an int to a Lua value and pushes it on the stack.
*/
diff --git a/lib/frrscript.c b/lib/frrscript.c
index 0e0d3c030c..4fee79991a 100644
--- a/lib/frrscript.c
+++ b/lib/frrscript.c
@@ -32,6 +32,96 @@
DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
+/*
+ * Script name hash utilities
+ */
+
+struct frrscript_names_head frrscript_names_hash;
+
+/*
+ * Wrapper for frrscript_names_add
+ * Use this to register hook calls when a daemon starts up
+ */
+int frrscript_names_add_function_name(const char *function_name)
+{
+ struct frrscript_names_entry *insert =
+ XCALLOC(MTYPE_SCRIPT, sizeof(*insert));
+ strlcpy(insert->function_name, function_name,
+ sizeof(insert->function_name));
+
+ if (frrscript_names_add(&frrscript_names_hash, insert)) {
+ zlog_warn(
+ "Failed to add hook call function name to script_names");
+ return 1;
+ }
+ return 0;
+}
+
+void frrscript_names_destroy(void)
+{
+ struct frrscript_names_entry *ne;
+
+ while ((ne = frrscript_names_pop(&frrscript_names_hash)))
+ XFREE(MTYPE_SCRIPT, ne);
+}
+
+/*
+ * Given a function_name, set its script_name. function_names and script_names
+ * are one-to-one. Each set will wipe the previous script_name.
+ * Return 0 if set was successful, else 1.
+ *
+ * script_name is the base name of the file, without .lua.
+ */
+int frrscript_names_set_script_name(const char *function_name,
+ const char *script_name)
+{
+ struct frrscript_names_entry lookup;
+
+ strlcpy(lookup.function_name, function_name,
+ sizeof(lookup.function_name));
+ struct frrscript_names_entry *snhe =
+ frrscript_names_find(&frrscript_names_hash, &lookup);
+ if (!snhe)
+ return 1;
+ strlcpy(snhe->script_name, script_name, sizeof(snhe->script_name));
+ return 0;
+}
+
+/*
+ * Given a function_name, get its script_name.
+ * Return NULL if function_name not found.
+ *
+ * script_name is the base name of the file, without .lua.
+ */
+char *frrscript_names_get_script_name(const char *function_name)
+{
+ struct frrscript_names_entry lookup;
+
+ strlcpy(lookup.function_name, function_name,
+ sizeof(lookup.function_name));
+ struct frrscript_names_entry *snhe =
+ frrscript_names_find(&frrscript_names_hash, &lookup);
+ if (!snhe)
+ return NULL;
+
+ if (snhe->script_name[0] == '\0')
+ return NULL;
+
+ return snhe->script_name;
+}
+
+uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe)
+{
+ return string_hash_make(snhe->function_name);
+}
+
+int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1,
+ const struct frrscript_names_entry *snhe2)
+{
+ return strncmp(snhe1->function_name, snhe2->function_name,
+ sizeof(snhe1->function_name));
+}
+
/* Codecs */
struct frrscript_codec frrscript_codecs_lib[] = {
@@ -226,7 +316,7 @@ void *frrscript_get_result(struct frrscript *fs, const char *function_name,
p = lua_to(lfs->L, 2);
/* At the end, the Lua state should be same as it was at the start
- * i.e. containing soley the returned table.
+ * i.e. containing solely the returned table.
*/
assert(lua_gettop(lfs->L) == 1);
assert(lua_istable(lfs->L, -1) == 1);
diff --git a/lib/frrscript.h b/lib/frrscript.h
index c089df61fc..4db3e6f1b2 100644
--- a/lib/frrscript.h
+++ b/lib/frrscript.h
@@ -24,6 +24,8 @@
#ifdef HAVE_SCRIPTING
#include <lua.h>
+#include <nexthop.h>
+#include <nexthop_group.h>
#include "frrlua.h"
#include "bgpd/bgp_script.h" // for peer and attr encoders/decoders
@@ -31,6 +33,43 @@
extern "C" {
#endif
+/* Forward declarations */
+extern struct zebra_dplane_ctx ctx;
+extern void lua_pushzebra_dplane_ctx(lua_State *L,
+ const struct zebra_dplane_ctx *ctx);
+extern void lua_decode_zebra_dplane_ctx(lua_State *L, int idx,
+ struct zebra_dplane_ctx *ctx);
+
+/*
+ * Script name hash
+ */
+PREDECL_HASH(frrscript_names);
+
+struct frrscript_names_entry {
+ /* Name of a Lua hook call */
+ char function_name[MAXPATHLEN];
+
+ /* Lua script in which to look for it */
+ char script_name[MAXPATHLEN];
+
+ struct frrscript_names_item item;
+};
+
+extern struct frrscript_names_head frrscript_names_hash;
+
+int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1,
+ const struct frrscript_names_entry *snhe2);
+uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe);
+
+DECLARE_HASH(frrscript_names, struct frrscript_names_entry, item,
+ frrscript_names_hash_cmp, frrscript_names_hash_key);
+
+int frrscript_names_add_function_name(const char *function_name);
+void frrscript_names_destroy(void);
+int frrscript_names_set_script_name(const char *function_name,
+ const char *script_name);
+char *frrscript_names_get_script_name(const char *function_name);
+
typedef void (*encoder_func)(lua_State *, const void *);
typedef void *(*decoder_func)(lua_State *, int);
@@ -171,7 +210,12 @@ time_t * : lua_pushtimet, \
char * : lua_pushstring_wrapper, \
struct attr * : lua_pushattr, \
struct peer * : lua_pushpeer, \
-const struct prefix * : lua_pushprefix \
+const struct prefix * : lua_pushprefix, \
+const struct ipaddr * : lua_pushipaddr, \
+const struct ethaddr * : lua_pushethaddr, \
+const struct nexthop_group * : lua_pushnexthop_group, \
+const struct nexthop * : lua_pushnexthop, \
+struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \
)((L), (value))
#define DECODE_ARGS_WITH_STATE(L, value) \
@@ -187,7 +231,12 @@ time_t * : lua_decode_timet, \
char * : lua_decode_stringp, \
struct attr * : lua_decode_attr, \
struct peer * : lua_decode_noop, \
-const struct prefix * : lua_decode_noop \
+const struct prefix * : lua_decode_noop, \
+const struct ipaddr * : lua_decode_noop, \
+const struct ethaddr * : lua_decode_noop, \
+const struct nexthop_group * : lua_decode_noop, \
+const struct nexthop * : lua_decode_noop, \
+struct zebra_dplane_ctx * : lua_decode_noop \
)((L), -1, (value))
/*
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index 209765bd6f..f9778c5d4c 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -395,6 +395,7 @@ DEFUN (grammar_findambig,
vector_slot(cmdvec, scannode++);
if (!cnode)
continue;
+ cmd_finalize_node(cnode);
nodegraph = cnode->cmdgraph;
if (!nodegraph)
continue;
@@ -466,6 +467,7 @@ DEFUN (grammar_access,
}
vty_out(vty, "node %d\n", (int)cnode->node);
+ cmd_finalize_node(cnode);
nodegraph = cnode->cmdgraph;
return CMD_SUCCESS;
}
diff --git a/lib/graph.c b/lib/graph.c
index 1cbe1b90f9..ba7314fb25 100644
--- a/lib/graph.c
+++ b/lib/graph.c
@@ -69,7 +69,7 @@ static void graph_vector_remove(vector v, unsigned int ix)
* and v->active is > ix. */
v->active--;
/* if ix == v->active--, we set the item to itself, then to NULL...
- * still correct, no check neccessary. */
+ * still correct, no check necessary. */
v->index[ix] = v->index[v->active];
v->index[v->active] = NULL;
}
diff --git a/lib/hash.h b/lib/hash.h
index 47d951a34b..f3b24f051b 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -161,7 +161,7 @@ hash_create_size(unsigned int size, unsigned int (*hash_key)(const void *),
* an element from its key, you must provide the data item itself, with the
* portions used in the hash function set to the same values as the data item
* to retrieve. To insert a data element, either provide the key as just
- * described and provide alloc_func as descrbied below to allocate the full
+ * described and provide alloc_func as described below to allocate the full
* data element, or provide the full data element and pass 'hash_alloc_intern'
* to alloc_func.
*
diff --git a/lib/hook.h b/lib/hook.h
index 3a0db6009b..d75e623edc 100644
--- a/lib/hook.h
+++ b/lib/hook.h
@@ -193,7 +193,7 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
* usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2));
* as above, "passlist" must use the same order and same names as "arglist"
*
- * theoretically passlist is not neccessary, but let's keep things simple and
+ * theoretically passlist is not necessary, but let's keep things simple and
* use exact same args on DECLARE and DEFINE.
*/
#define DECLARE_HOOK(hookname, arglist, passlist) \
diff --git a/lib/if.c b/lib/if.c
index 424880ff42..99fa83719a 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -45,8 +45,10 @@ DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
+static void if_set_name(struct interface *ifp, const char *name);
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
vrf_id_t vrf_id);
+static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex);
static int if_cmp_func(const struct interface *, const struct interface *);
static int if_cmp_index_func(const struct interface *ifp1,
const struct interface *ifp2);
@@ -153,16 +155,18 @@ static void ifp_connected_free(void *arg)
}
/* Create new interface structure. */
-static struct interface *if_new(vrf_id_t vrf_id)
+static struct interface *if_new(struct vrf *vrf)
{
struct interface *ifp;
+ assert(vrf);
+
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
ifp->ifindex = IFINDEX_INTERNAL;
ifp->name[0] = '\0';
- ifp->vrf_id = vrf_id;
+ ifp->vrf = vrf;
ifp->connected = list_new();
ifp->connected->del = ifp_connected_free;
@@ -207,11 +211,11 @@ void if_down_via_zapi(struct interface *ifp)
(*ifp_master.down_hook)(ifp);
}
-struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
+static struct interface *if_create_name(const char *name, struct vrf *vrf)
{
struct interface *ifp;
- ifp = if_new(vrf_id);
+ ifp = if_new(vrf);
if_set_name(ifp, name);
@@ -219,71 +223,28 @@ 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)
-{
- struct interface *ifp;
-
- ifp = if_new(vrf_id);
-
- if_set_index(ifp, ifindex);
-
- hook_call(if_add, ifp);
- return ifp;
-}
-
/* Create new interface structure. */
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
{
struct vrf *old_vrf, *vrf;
/* remove interface from old master vrf list */
- old_vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (old_vrf) {
- if (ifp->name[0] != '\0')
- IFNAME_RB_REMOVE(old_vrf, ifp);
+ old_vrf = ifp->vrf;
- if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_REMOVE(old_vrf, ifp);
- }
+ if (ifp->name[0] != '\0')
+ IFNAME_RB_REMOVE(old_vrf, ifp);
- ifp->vrf_id = vrf_id;
- vrf = vrf_get(ifp->vrf_id, NULL);
+ if (ifp->ifindex != IFINDEX_INTERNAL)
+ IFINDEX_RB_REMOVE(old_vrf, ifp);
+
+ vrf = vrf_get(vrf_id, NULL);
+ ifp->vrf = vrf;
if (ifp->name[0] != '\0')
IFNAME_RB_INSERT(vrf, ifp);
if (ifp->ifindex != IFINDEX_INTERNAL)
IFINDEX_RB_INSERT(vrf, ifp);
-
- /*
- * HACK: Change the interface VRF in the running configuration directly,
- * bypassing the northbound layer. This is necessary to avoid deleting
- * the interface and readding it in the new VRF, which would have
- * several implications.
- */
- if (yang_module_find("frr-interface")) {
- struct lyd_node *if_dnode;
- char oldpath[XPATH_MAXLEN];
- char newpath[XPATH_MAXLEN];
-
- snprintf(oldpath, sizeof(oldpath),
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifp->name, old_vrf->name);
- snprintf(newpath, sizeof(newpath),
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifp->name, vrf->name);
-
- if_dnode = yang_dnode_getf(running_config->dnode, "%s/vrf",
- oldpath);
-
- if (if_dnode) {
- yang_dnode_change_leaf(if_dnode, vrf->name);
- nb_running_move_tree(oldpath, newpath);
- running_config->version++;
- }
-
- vty_update_xpath(oldpath, newpath);
- }
}
@@ -304,10 +265,7 @@ void if_delete_retain(struct interface *ifp)
void if_delete(struct interface **ifp)
{
struct interface *ptr = *ifp;
- struct vrf *vrf;
-
- vrf = vrf_lookup_by_id(ptr->vrf_id);
- assert(vrf);
+ struct vrf *vrf = ptr->vrf;
IFNAME_RB_REMOVE(vrf, ptr);
if (ptr->ifindex != IFINDEX_INTERNAL)
@@ -341,7 +299,7 @@ static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
return RB_FIND(if_index_head, &vrf->ifaces_by_index, &if_tmp);
}
-/* Interface existance check by index. */
+/* Interface existence check by index. */
struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
{
switch (vrf_get_backend()) {
@@ -354,7 +312,7 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
return NULL;
}
-/* Interface existance check by index. */
+/* Interface existence check by index. */
struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex,
vrf_id_t vrf_id)
{
@@ -406,7 +364,7 @@ ifindex_t ifname2ifindex(const char *name, vrf_id_t vrf_id)
: IFINDEX_INTERNAL;
}
-/* Interface existance check by interface name. */
+/* Interface existence check by interface name. */
struct interface *if_lookup_by_name(const char *name, vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
@@ -431,7 +389,7 @@ struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf)
return RB_FIND(if_name_head, &vrf->ifaces_by_name, &if_tmp);
}
-struct interface *if_lookup_by_name_all_vrf(const char *name)
+static struct interface *if_lookup_by_name_all_vrf(const char *name)
{
struct vrf *vrf;
struct interface *ifp;
@@ -439,8 +397,8 @@ struct interface *if_lookup_by_name_all_vrf(const char *name)
if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ)
return NULL;
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- ifp = if_lookup_by_name(name, vrf->vrf_id);
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ ifp = if_lookup_by_name_vrf(name, vrf);
if (ifp)
return ifp;
}
@@ -448,7 +406,7 @@ struct interface *if_lookup_by_name_all_vrf(const char *name)
return NULL;
}
-struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
+static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
{
struct vrf *vrf;
struct interface *ifp;
@@ -465,36 +423,51 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
return NULL;
}
-/* Lookup interface by IP address. */
-struct interface *if_lookup_exact_address(const void *src, int family,
+/* Lookup interface by IP address.
+ *
+ * supersedes if_lookup_exact_address(), which didn't care about up/down
+ * state. but all users we have either only care if the address is local
+ * (=> use if_address_is_local() please), or care about UP interfaces before
+ * anything else
+ *
+ * to accept only UP interfaces, check if_is_up() on the returned ifp.
+ */
+struct interface *if_lookup_address_local(const void *src, int family,
vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct listnode *cnode;
- struct interface *ifp;
+ struct interface *ifp, *best_down = NULL;
struct prefix *p;
struct connected *c;
+ if (family != AF_INET && family != AF_INET6)
+ return NULL;
+
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
p = c->address;
- if (p && (p->family == family)) {
- if (family == AF_INET) {
- if (IPV4_ADDR_SAME(
- &p->u.prefix4,
+ if (!p || p->family != family)
+ continue;
+
+ if (family == AF_INET) {
+ if (!IPV4_ADDR_SAME(&p->u.prefix4,
(struct in_addr *)src))
- return ifp;
- } else if (family == AF_INET6) {
- if (IPV6_ADDR_SAME(
- &p->u.prefix6,
+ continue;
+ } else if (family == AF_INET6) {
+ if (!IPV6_ADDR_SAME(&p->u.prefix6,
(struct in6_addr *)src))
- return ifp;
- }
+ continue;
}
+
+ if (if_is_up(ifp))
+ return ifp;
+ if (!best_down)
+ best_down = ifp;
}
}
- return NULL;
+ return best_down;
}
/* Lookup interface by IP address. */
@@ -582,81 +555,67 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
/* Get interface by name if given name interface doesn't exist create
one. */
-struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
+struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id,
+ const char *vrf_name)
{
- struct interface *ifp;
+ struct interface *ifp = NULL;
+ struct vrf *vrf;
switch (vrf_get_backend()) {
case VRF_BACKEND_UNKNOWN:
case VRF_BACKEND_NETNS:
- ifp = if_lookup_by_name(name, vrf_id);
- if (ifp)
- return ifp;
- return if_create_name(name, vrf_id);
- case VRF_BACKEND_VRF_LITE:
- ifp = if_lookup_by_name_all_vrf(name);
+ vrf = vrf_get(vrf_id, vrf_name);
+ assert(vrf);
+
+ ifp = if_lookup_by_name_vrf(name, vrf);
if (ifp) {
- if (ifp->vrf_id == vrf_id)
- return ifp;
/* If it came from the kernel or by way of zclient,
* believe it and update the ifp accordingly.
*/
- if_update_to_new_vrf(ifp, vrf_id);
+ if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
+ if_update_to_new_vrf(ifp, vrf_id);
+
return ifp;
}
- return if_create_name(name, vrf_id);
- }
- return NULL;
-}
-
-struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
-{
- struct interface *ifp;
-
- switch (vrf_get_backend()) {
- case VRF_BACKEND_UNKNOWN:
- case VRF_BACKEND_NETNS:
- ifp = if_lookup_by_ifindex(ifindex, vrf_id);
- if (ifp)
- return ifp;
- return if_create_ifindex(ifindex, vrf_id);
+ break;
case VRF_BACKEND_VRF_LITE:
- ifp = if_lookup_by_index_all_vrf(ifindex);
+ ifp = if_lookup_by_name_all_vrf(name);
if (ifp) {
- if (ifp->vrf_id == vrf_id)
- return ifp;
/* If it came from the kernel or by way of zclient,
* believe it and update the ifp accordingly.
*/
- if_update_to_new_vrf(ifp, vrf_id);
+ if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN)
+ if_update_to_new_vrf(ifp, vrf_id);
+
return ifp;
}
- return if_create_ifindex(ifindex, vrf_id);
+
+ vrf = vrf_get(vrf_id, vrf_name);
+ assert(vrf);
+
+ break;
+ default:
+ return NULL;
}
- return NULL;
+ return if_create_name(name, vrf);
}
int if_set_index(struct interface *ifp, ifindex_t ifindex)
{
- struct vrf *vrf;
-
if (ifp->ifindex == ifindex)
return 0;
- vrf = vrf_get(ifp->vrf_id, NULL);
- assert(vrf);
-
/*
* If there is already an interface with this ifindex, we will collide
* on insertion, so don't even try.
*/
- if (if_lookup_by_ifindex(ifindex, ifp->vrf_id))
+ if (if_lookup_by_ifindex(ifindex, ifp->vrf->vrf_id))
return -1;
if (ifp->ifindex != IFINDEX_INTERNAL)
- IFINDEX_RB_REMOVE(vrf, ifp);
+ IFINDEX_RB_REMOVE(ifp->vrf, ifp);
ifp->ifindex = ifindex;
@@ -666,30 +625,25 @@ int if_set_index(struct interface *ifp, ifindex_t ifindex)
* already an interface with the desired ifindex at the top of
* the function. Nevertheless.
*/
- if (IFINDEX_RB_INSERT(vrf, ifp))
+ if (IFINDEX_RB_INSERT(ifp->vrf, ifp))
return -1;
}
return 0;
}
-void if_set_name(struct interface *ifp, const char *name)
+static void if_set_name(struct interface *ifp, const char *name)
{
- struct vrf *vrf;
-
- vrf = vrf_get(ifp->vrf_id, NULL);
- assert(vrf);
-
if (if_cmp_name_func(ifp->name, name) == 0)
return;
if (ifp->name[0] != '\0')
- IFNAME_RB_REMOVE(vrf, ifp);
+ IFNAME_RB_REMOVE(ifp->vrf, ifp);
strlcpy(ifp->name, name, sizeof(ifp->name));
if (ifp->name[0] != '\0')
- IFNAME_RB_INSERT(vrf, ifp);
+ IFNAME_RB_INSERT(ifp->vrf, ifp);
}
/* Does interface up ? */
@@ -727,7 +681,7 @@ int if_is_no_ptm_operative(const struct interface *ifp)
}
/* Is this loopback interface ? */
-int if_is_loopback(const struct interface *ifp)
+int if_is_loopback_exact(const struct interface *ifp)
{
/* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M
* but Y on platform N?
@@ -741,9 +695,10 @@ int if_is_vrf(const struct interface *ifp)
return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
}
-bool if_is_loopback_or_vrf(const struct interface *ifp)
+/* Should this interface be treated as a loopback? */
+bool if_is_loopback(const struct interface *ifp)
{
- if (if_is_loopback(ifp) || if_is_vrf(ifp))
+ if (if_is_loopback_exact(ifp) || if_is_vrf(ifp))
return true;
return false;
@@ -817,15 +772,12 @@ static void if_dump(const struct interface *ifp)
struct listnode *node;
struct connected *c __attribute__((unused));
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) {
- struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
-
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c))
zlog_info(
"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,
+ ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
+ ifp->ifindex, ifp->metric, ifp->mtu, ifp->mtu6,
if_flag_dump(ifp->flags));
- }
}
/* Interface printing for all interface. */
@@ -894,16 +846,14 @@ connected_log(struct connected *connected, char *str)
{
struct prefix *p;
struct interface *ifp;
- struct vrf *vrf;
char logbuf[BUFSIZ];
char buf[BUFSIZ];
ifp = connected->ifp;
p = connected->address;
- vrf = vrf_lookup_by_id(ifp->vrf_id);
snprintf(logbuf, sizeof(logbuf), "%s interface %s vrf %s(%u) %s %pFX ",
- str, ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id,
+ str, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id,
prefix_family_str(p), p);
p = connected->destination;
@@ -1059,30 +1009,15 @@ struct connected *connected_get_linklocal(struct interface *ifp)
void if_terminate(struct vrf *vrf)
{
struct interface *ifp;
- bool delete;
-
- /*
- * If the default VRF is being terminated or has
- * already been terminated it means that
- * the program is shutting down and we need to
- * delete all the interfaces. Otherwise, we only
- * need to move VRF's interfaces to the default VRF.
- */
- delete = vrf_is_backend_netns() || vrf->vrf_id == VRF_DEFAULT
- || !vrf_lookup_by_id(VRF_DEFAULT);
while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);
- if (delete) {
- if (ifp->node) {
- ifp->node->info = NULL;
- route_unlock_node(ifp->node);
- }
- if_delete(&ifp);
- } else {
- if_update_to_new_vrf(ifp, VRF_DEFAULT);
+ if (ifp->node) {
+ ifp->node->info = NULL;
+ route_unlock_node(ifp->node);
}
+ if_delete(&ifp);
}
}
@@ -1108,6 +1043,8 @@ const char *if_link_type_str(enum zebra_link_type llt)
llts(ZEBRA_LLT_CSLIP, "Compressed SLIP");
llts(ZEBRA_LLT_SLIP6, "SLIPv6");
llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6");
+ llts(ZEBRA_LLT_RSRVD, "Reserved");
+ llts(ZEBRA_LLT_ADAPT, "Adapt");
llts(ZEBRA_LLT_ROSE, "ROSE packet radio");
llts(ZEBRA_LLT_X25, "CCITT X.25");
llts(ZEBRA_LLT_PPP, "PPP");
@@ -1124,8 +1061,10 @@ const char *if_link_type_str(enum zebra_link_type llt)
llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT");
llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel");
llts(ZEBRA_LLT_IPGRE, "GRE over IP");
+ llts(ZEBRA_LLT_IP6GRE, "GRE over IPv6");
llts(ZEBRA_LLT_PIMREG, "PIMSM registration");
llts(ZEBRA_LLT_HIPPI, "HiPPI");
+ llts(ZEBRA_LLT_ECONET, "Acorn Econet");
llts(ZEBRA_LLT_IRDA, "IrDA");
llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP");
llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop");
@@ -1136,9 +1075,6 @@ const char *if_link_type_str(enum zebra_link_type llt)
llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap");
llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4");
llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy");
- default:
- flog_err(EC_LIB_DEVELOPMENT, "Unknown value %d", llt);
- return "Unknown type!";
#undef llts
}
return NULL;
@@ -1185,6 +1121,25 @@ void if_link_params_free(struct interface *ifp)
/* ----------- CLI commands ----------- */
+/* Guess the VRF of an interface. */
+static int vrfname_by_ifname(const char *ifname, const char **vrfname)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+ int count = 0;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (strmatch(ifp->name, ifname)) {
+ *vrfname = vrf->name;
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+
/*
* XPath: /frr-interface:lib/interface
*/
@@ -1196,50 +1151,30 @@ DEFPY_YANG_NOSH (interface,
VRF_CMD_HELP_STR)
{
char xpath_list[XPATH_MAXLEN];
- vrf_id_t vrf_id;
struct interface *ifp;
- int ret;
-
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
-
- /*
- * This command requires special handling to maintain backward
- * compatibility. If a VRF name is not specified, it means we're willing
- * to accept any interface with the given name on any VRF. If no
- * interface is found, then a new one should be created on the default
- * VRF.
- */
- VRF_GET_ID(vrf_id, vrf_name, false);
- ifp = if_lookup_by_name_all_vrf(ifname);
- if (ifp && ifp->vrf_id != vrf_id) {
- struct vrf *vrf;
+ struct vrf *vrf;
+ int ret, count;
+ if (vrf_is_backend_netns()) {
/*
- * Special case 1: a VRF name was specified, but the found
- * interface is associated to different VRF. Reject the command.
+ * For backward compatibility, if the VRF name is not specified
+ * and there is exactly one interface with this name in the
+ * system, use its VRF. Otherwise fallback to the default VRF.
*/
- if (vrf_id != VRF_DEFAULT) {
- vty_out(vty, "%% interface %s not in %s vrf\n", ifname,
- vrf_name);
- return CMD_WARNING_CONFIG_FAILED;
+ if (!vrf_name) {
+ count = vrfname_by_ifname(ifname, &vrf_name);
+ if (count != 1)
+ vrf_name = VRF_DEFAULT_NAME;
}
- /*
- * Special case 2: a VRF name was *not* specified, and the found
- * interface is associated to a VRF other than the default one.
- * Update vrf_id and vrf_name to account for that.
- */
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- assert(vrf);
- vrf_id = ifp->vrf_id;
- vrf_name = vrf->name;
+ snprintf(xpath_list, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s:%s']", vrf_name,
+ ifname);
+ } else {
+ snprintf(xpath_list, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s']", ifname);
}
- snprintf(xpath_list, sizeof(xpath_list),
- "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname,
- vrf_name);
-
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
ret = nb_cli_apply_changes_clear_pending(vty, xpath_list);
if (ret == CMD_SUCCESS) {
@@ -1251,7 +1186,15 @@ DEFPY_YANG_NOSH (interface,
* all interface-level commands are converted to the new
* northbound model.
*/
- ifp = if_lookup_by_name(ifname, vrf_id);
+ if (vrf_is_backend_netns()) {
+ vrf = vrf_lookup_by_name(vrf_name);
+ if (vrf)
+ ifp = if_lookup_by_name_vrf(ifname, vrf);
+ else
+ ifp = NULL;
+ } else {
+ ifp = if_lookup_by_name_all_vrf(ifname);
+ }
if (ifp)
VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp);
}
@@ -1267,31 +1210,77 @@ DEFPY_YANG (no_interface,
"Interface's name\n"
VRF_CMD_HELP_STR)
{
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
+ char xpath_list[XPATH_MAXLEN];
+ int count;
+
+ if (vrf_is_backend_netns()) {
+ /*
+ * For backward compatibility, if the VRF name is not specified
+ * and there is exactly one interface with this name in the
+ * system, use its VRF. Otherwise fallback to the default VRF.
+ */
+ if (!vrf_name) {
+ count = vrfname_by_ifname(ifname, &vrf_name);
+ if (count != 1)
+ vrf_name = VRF_DEFAULT_NAME;
+ }
+
+ snprintf(xpath_list, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s:%s']", vrf_name,
+ ifname);
+ } else {
+ snprintf(xpath_list, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s']", ifname);
+ }
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(
- vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifname, vrf_name);
+ return nb_cli_apply_changes(vty, xpath_list);
}
-static void cli_show_interface(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults)
+static void netns_ifname_split(const char *xpath, char *ifname, char *vrfname)
{
- const char *vrf;
+ char *delim;
+ int len;
- vrf = yang_dnode_get_string(dnode, "./vrf");
+ assert(vrf_is_backend_netns());
+ delim = strchr(xpath, ':');
+ assert(delim);
+
+ len = delim - xpath;
+ memcpy(vrfname, xpath, len);
+ vrfname[len] = 0;
+
+ strlcpy(ifname, delim + 1, XPATH_MAXLEN);
+}
+
+static void cli_show_interface(struct vty *vty, const struct lyd_node *dnode,
+ bool show_defaults)
+{
vty_out(vty, "!\n");
- vty_out(vty, "interface %s", yang_dnode_get_string(dnode, "./name"));
- if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, " vrf %s", vrf);
+
+ if (vrf_is_backend_netns()) {
+ char ifname[XPATH_MAXLEN];
+ char vrfname[XPATH_MAXLEN];
+
+ netns_ifname_split(yang_dnode_get_string(dnode, "./name"),
+ ifname, vrfname);
+
+ vty_out(vty, "interface %s", ifname);
+ if (!strmatch(vrfname, VRF_DEFAULT_NAME))
+ vty_out(vty, " vrf %s", vrfname);
+ } else {
+ const char *ifname = yang_dnode_get_string(dnode, "./name");
+
+ vty_out(vty, "interface %s", ifname);
+ }
+
vty_out(vty, "\n");
}
-static void cli_show_interface_end(struct vty *vty, struct lyd_node *dnode)
+static void cli_show_interface_end(struct vty *vty,
+ const struct lyd_node *dnode)
{
vty_out(vty, "exit\n");
}
@@ -1327,8 +1316,9 @@ DEFPY_YANG (no_interface_desc,
return nb_cli_apply_changes(vty, NULL);
}
-static void cli_show_interface_desc(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults)
+static void cli_show_interface_desc(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
{
vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
}
@@ -1361,6 +1351,20 @@ static struct cmd_node interface_node = {
.prompt = "%s(config-if)# ",
};
+static int if_config_write_single(const struct lyd_node *dnode, void *arg)
+{
+ nb_cli_show_dnode_cmds(arg, dnode, false);
+
+ return YANG_ITER_CONTINUE;
+}
+
+static int if_nb_config_write(struct vty *vty)
+{
+ yang_dnode_iterate(if_config_write_single, vty, running_config->dnode,
+ "/frr-interface:lib/interface");
+ return 1;
+}
+
void if_cmd_init(int (*config_write)(struct vty *))
{
cmd_variable_handler_register(if_var_handlers);
@@ -1376,6 +1380,11 @@ void if_cmd_init(int (*config_write)(struct vty *))
install_element(INTERFACE_NODE, &no_interface_desc_cmd);
}
+void if_cmd_init_default(void)
+{
+ if_cmd_init(if_nb_config_write);
+}
+
void if_zapi_callbacks(int (*create)(struct interface *ifp),
int (*up)(struct interface *ifp),
int (*down)(struct interface *ifp),
@@ -1395,37 +1404,35 @@ void if_zapi_callbacks(int (*create)(struct interface *ifp),
static int lib_interface_create(struct nb_cb_create_args *args)
{
const char *ifname;
- const char *vrfname;
- struct vrf *vrf;
struct interface *ifp;
ifname = yang_dnode_get_string(args->dnode, "./name");
- vrfname = yang_dnode_get_string(args->dnode, "./vrf");
switch (args->event) {
case NB_EV_VALIDATE:
- vrf = vrf_lookup_by_name(vrfname);
- if (!vrf) {
- zlog_warn("%s: VRF %s doesn't exist", __func__,
- vrfname);
- return NB_ERR_VALIDATION;
- }
- if (vrf->vrf_id == VRF_UNKNOWN) {
- zlog_warn("%s: VRF %s is not active", __func__,
- vrf->name);
- return NB_ERR_VALIDATION;
- }
+ if (vrf_is_backend_netns()) {
+ char ifname_ns[XPATH_MAXLEN];
+ char vrfname_ns[XPATH_MAXLEN];
- /* if VRF is netns or not yet known - init for instance
- * then assumption is that passed config is exact
- * then the user intent was not to use an other iface
- */
- if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
- ifp = if_lookup_by_name_all_vrf(ifname);
- if (ifp && ifp->vrf_id != vrf->vrf_id) {
- zlog_warn(
- "%s: interface %s already exists in another VRF",
- __func__, ifp->name);
+ netns_ifname_split(ifname, ifname_ns, vrfname_ns);
+
+ if (strlen(ifname_ns) > 16) {
+ snprintf(
+ args->errmsg, args->errmsg_len,
+ "Maximum interface name length is 16 characters");
+ return NB_ERR_VALIDATION;
+ }
+ if (strlen(vrfname_ns) > 36) {
+ snprintf(
+ args->errmsg, args->errmsg_len,
+ "Maximum VRF name length is 36 characters");
+ return NB_ERR_VALIDATION;
+ }
+ } else {
+ if (strlen(ifname) > 16) {
+ snprintf(
+ args->errmsg, args->errmsg_len,
+ "Maximum interface name length is 16 characters");
return NB_ERR_VALIDATION;
}
}
@@ -1434,9 +1441,18 @@ static int lib_interface_create(struct nb_cb_create_args *args)
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = vrf_lookup_by_name(vrfname);
- assert(vrf);
- ifp = if_get_by_name(ifname, vrf->vrf_id);
+ if (vrf_is_backend_netns()) {
+ char ifname_ns[XPATH_MAXLEN];
+ char vrfname_ns[XPATH_MAXLEN];
+
+ netns_ifname_split(ifname, ifname_ns, vrfname_ns);
+
+ ifp = if_get_by_name(ifname_ns, VRF_UNKNOWN,
+ vrfname_ns);
+ } else {
+ ifp = if_get_by_name(ifname, VRF_UNKNOWN,
+ VRF_DEFAULT_NAME);
+ }
ifp->configured = true;
nb_running_set_entry(args->dnode, ifp);
@@ -1449,7 +1465,7 @@ static int lib_interface_create(struct nb_cb_create_args *args)
static int lib_interface_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
-
+ struct vrf *vrf;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1465,9 +1481,13 @@ static int lib_interface_destroy(struct nb_cb_destroy_args *args)
break;
case NB_EV_APPLY:
ifp = nb_running_unset_entry(args->dnode);
+ vrf = ifp->vrf;
ifp->configured = false;
if_delete(&ifp);
+
+ if (!vrf_is_enabled(vrf))
+ vrf_delete(vrf);
break;
}
@@ -1487,7 +1507,7 @@ static const void *lib_interface_get_next(struct nb_cb_get_next_args *args)
assert(vrf);
pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
} else {
- vrf = vrf_lookup_by_id(pif->vrf_id);
+ vrf = pif->vrf;
pif = RB_NEXT(if_name_head, pif);
/* if no more interfaces, switch to next vrf */
while (pif == NULL) {
@@ -1505,13 +1525,14 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args)
{
const struct interface *ifp = args->list_entry;
- struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+ args->keys->num = 1;
- assert(vrf);
-
- args->keys->num = 2;
- strlcpy(args->keys->key[0], ifp->name, sizeof(args->keys->key[0]));
- strlcpy(args->keys->key[1], vrf->name, sizeof(args->keys->key[1]));
+ if (vrf_is_backend_netns())
+ snprintf(args->keys->key[0], sizeof(args->keys->key[0]),
+ "%s:%s", ifp->vrf->name, ifp->name);
+ else
+ snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s",
+ ifp->name);
return NB_OK;
}
@@ -1519,11 +1540,19 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args)
static const void *
lib_interface_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
- const char *ifname = args->keys->key[0];
- const char *vrfname = args->keys->key[1];
- struct vrf *vrf = vrf_lookup_by_name(vrfname);
+ if (vrf_is_backend_netns()) {
+ char ifname[XPATH_MAXLEN];
+ char vrfname[XPATH_MAXLEN];
+ struct vrf *vrf;
+
+ netns_ifname_split(args->keys->key[0], ifname, vrfname);
+
+ vrf = vrf_lookup_by_name(vrfname);
- return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL;
+ return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL;
+ } else {
+ return if_lookup_by_name_all_vrf(args->keys->key[0]);
+ }
}
/*
@@ -1559,6 +1588,17 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args)
}
/*
+ * XPath: /frr-interface:lib/interface/vrf
+ */
+static struct yang_data *
+lib_interface_vrf_get_elem(struct nb_cb_get_elem_args *args)
+{
+ const struct interface *ifp = args->list_entry;
+
+ return yang_data_new_string(args->xpath, ifp->vrf->name);
+}
+
+/*
* XPath: /frr-interface:lib/interface/state/if-index
*/
static struct yang_data *
@@ -1672,6 +1712,12 @@ const struct frr_yang_module_info frr_interface_info = {
},
},
{
+ .xpath = "/frr-interface:lib/interface/vrf",
+ .cbs = {
+ .get_elem = lib_interface_vrf_get_elem,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/state/if-index",
.cbs = {
.get_elem = lib_interface_state_if_index_get_elem,
diff --git a/lib/if.h b/lib/if.h
index 43e2d3cffa..c8f4d9ab9d 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -251,8 +251,8 @@ struct interface {
/* Interface MTU. */
unsigned int mtu; /* IPv4 MTU */
unsigned int
- mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu
- */
+ mtu6; /* IPv6 MTU - probably, but not necessarily same as mtu
+ */
/* Link-layer information and hardware address */
enum zebra_link_type ll_type;
@@ -293,7 +293,8 @@ struct interface {
#endif /* HAVE_NET_RT_IFLIST */
struct route_node *node;
- vrf_id_t vrf_id;
+
+ struct vrf *vrf;
/*
* Has the end users entered `interface XXXX` from the cli in some
@@ -310,56 +311,56 @@ RB_HEAD(if_index_head, interface);
RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func)
DECLARE_QOBJ_TYPE(interface);
-#define IFNAME_RB_INSERT(vrf, ifp) \
+#define IFNAME_RB_INSERT(v, ifp) \
({ \
struct interface *_iz = \
- RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp)); \
+ RB_INSERT(if_name_head, &v->ifaces_by_name, (ifp)); \
if (_iz) \
flog_err( \
EC_LIB_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
- "name exists already in VRF %u!", \
- __func__, (ifp)->name, (ifp)->vrf_id); \
+ "name exists already in VRF %s!", \
+ __func__, (ifp)->name, (ifp)->vrf->name); \
_iz; \
})
-#define IFNAME_RB_REMOVE(vrf, ifp) \
+#define IFNAME_RB_REMOVE(v, ifp) \
({ \
struct interface *_iz = \
- RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)); \
+ RB_REMOVE(if_name_head, &v->ifaces_by_name, (ifp)); \
if (_iz == NULL) \
flog_err( \
EC_LIB_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
- "name doesn't exist in VRF %u!", \
- __func__, (ifp)->name, (ifp)->vrf_id); \
+ "name doesn't exist in VRF %s!", \
+ __func__, (ifp)->name, (ifp)->vrf->name); \
_iz; \
})
-#define IFINDEX_RB_INSERT(vrf, ifp) \
+#define IFINDEX_RB_INSERT(v, ifp) \
({ \
- struct interface *_iz = RB_INSERT( \
- if_index_head, &vrf->ifaces_by_index, (ifp)); \
+ struct interface *_iz = \
+ RB_INSERT(if_index_head, &v->ifaces_by_index, (ifp)); \
if (_iz) \
flog_err( \
EC_LIB_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
- "ifindex exists already in VRF %u!", \
- __func__, (ifp)->ifindex, (ifp)->vrf_id); \
+ "ifindex exists already in VRF %s!", \
+ __func__, (ifp)->ifindex, (ifp)->vrf->name); \
_iz; \
})
-#define IFINDEX_RB_REMOVE(vrf, ifp) \
+#define IFINDEX_RB_REMOVE(v, ifp) \
({ \
- struct interface *_iz = RB_REMOVE( \
- if_index_head, &vrf->ifaces_by_index, (ifp)); \
+ struct interface *_iz = \
+ RB_REMOVE(if_index_head, &v->ifaces_by_index, (ifp)); \
if (_iz == NULL) \
flog_err( \
EC_LIB_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
- "ifindex doesn't exist in VRF %u!", \
- __func__, (ifp)->ifindex, (ifp)->vrf_id); \
+ "ifindex doesn't exist in VRF %s!", \
+ __func__, (ifp)->ifindex, (ifp)->vrf->name); \
_iz; \
})
@@ -397,16 +398,12 @@ struct connected {
/*
The ZEBRA_IFC_REAL flag should be set if and only if this address
exists in the kernel and is actually usable. (A case where it exists
- but
- is not yet usable would be IPv6 with DAD)
+ but is not yet usable would be IPv6 with DAD)
The ZEBRA_IFC_CONFIGURED flag should be set if and only if this
- address
- was configured by the user from inside quagga.
+ address was configured by the user from inside frr.
The ZEBRA_IFC_QUEUED flag should be set if and only if the address
- exists
- in the kernel. It may and should be set although the address might
- not be
- usable yet. (compare with ZEBRA_IFC_REAL)
+ exists in the kernel. It may and should be set although the
+ address might not be usable yet. (compare with ZEBRA_IFC_REAL)
The ZEBRA_IFC_DOWN flag is used to record that an address is
present, but down/unavailable.
*/
@@ -510,16 +507,10 @@ extern int if_cmp_name_func(const char *p1, const char *p2);
*/
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
-/* Create new interface, adds to name list only */
-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);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
extern struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex,
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,
+extern struct interface *if_lookup_address_local(const void *matchaddr,
int family, vrf_id_t vrf_id);
extern struct connected *if_lookup_address(const void *matchaddr, int family,
vrf_id_t vrf_id);
@@ -528,17 +519,20 @@ extern struct interface *if_lookup_prefix(const struct prefix *prefix,
size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
struct interface ***result, vrf_id_t vrf_id);
+static inline bool if_address_is_local(const void *matchaddr, int family,
+ vrf_id_t vrf_id)
+{
+ return if_lookup_address_local(matchaddr, family, vrf_id) != NULL;
+}
+
struct vrf;
-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);
+extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id,
+ const char *vrf_name);
/* 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 */
-extern void if_set_name(struct interface *ifp, const char *name);
/* Delete the interface, but do not free the structure, and leave it in the
interface list. It is often advisable to leave the pseudo interface
@@ -553,9 +547,9 @@ extern int if_is_up(const struct interface *ifp);
extern int if_is_running(const struct interface *ifp);
extern int if_is_operative(const struct interface *ifp);
extern int if_is_no_ptm_operative(const struct interface *ifp);
-extern int if_is_loopback(const struct interface *ifp);
+extern int if_is_loopback_exact(const struct interface *ifp);
extern int if_is_vrf(const struct interface *ifp);
-extern bool if_is_loopback_or_vrf(const struct interface *ifp);
+extern bool if_is_loopback(const struct interface *ifp);
extern int if_is_broadcast(const struct interface *ifp);
extern int if_is_pointopoint(const struct interface *ifp);
extern int if_is_multicast(const struct interface *ifp);
@@ -599,6 +593,7 @@ void if_link_params_free(struct interface *);
/* Northbound. */
struct vty;
extern void if_cmd_init(int (*config_write)(struct vty *));
+extern void if_cmd_init_default(void);
extern void if_zapi_callbacks(int (*create)(struct interface *ifp),
int (*up)(struct interface *ifp),
int (*down)(struct interface *ifp),
diff --git a/lib/json.c b/lib/json.c
index cfba6ea3b6..854a3d59d1 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -39,17 +39,41 @@ bool use_json(const int argc, struct cmd_token *argv[])
return false;
}
+struct json_object *json_object_new_stringv(const char *fmt, va_list args)
+{
+ struct json_object *ret;
+ char *text, buf[256];
+
+ text = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt, args);
+ ret = json_object_new_string(text);
+
+ if (text != buf)
+ XFREE(MTYPE_TMP, text);
+ return ret;
+}
+
void json_array_string_add(json_object *json, const char *str)
{
json_object_array_add(json, json_object_new_string(str));
}
+void json_array_string_addv(json_object *json, const char *fmt, va_list args)
+{
+ json_object_array_add(json, json_object_new_stringv(fmt, args));
+}
+
void json_object_string_add(struct json_object *obj, const char *key,
const char *s)
{
json_object_object_add(obj, key, json_object_new_string(s));
}
+void json_object_string_addv(struct json_object *obj, const char *key,
+ const char *fmt, va_list args)
+{
+ json_object_object_add(obj, key, json_object_new_stringv(fmt, args));
+}
+
void json_object_int_add(struct json_object *obj, const char *key, int64_t i)
{
json_object_object_add(obj, key, json_object_new_int64(i));
diff --git a/lib/json.h b/lib/json.h
index fe208f4fa9..9d33ac7ae3 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -26,6 +26,7 @@ extern "C" {
#endif
#include "command.h"
+#include "printfrr.h"
#include <json-c/json.h>
/*
@@ -59,6 +60,53 @@ extern struct json_object *json_object_lock(struct json_object *obj);
extern void json_object_free(struct json_object *obj);
extern void json_array_string_add(json_object *json, const char *str);
+/* printfrr => json helpers */
+
+PRINTFRR(3, 0)
+extern void json_object_string_addv(struct json_object *obj, const char *key,
+ const char *fmt, va_list args);
+PRINTFRR(3, 4)
+static inline void json_object_string_addf(struct json_object *obj,
+ const char *key, const char *fmt,
+ ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ json_object_string_addv(obj, key, fmt, args);
+ va_end(args);
+}
+
+PRINTFRR(2, 0)
+extern void json_array_string_addv(json_object *json, const char *fmt,
+ va_list args);
+PRINTFRR(2, 3)
+static inline void json_array_string_addf(struct json_object *obj,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ json_array_string_addv(obj, fmt, args);
+ va_end(args);
+}
+
+PRINTFRR(1, 0)
+extern struct json_object *json_object_new_stringv(const char *fmt,
+ va_list args);
+PRINTFRR(1, 2)
+static inline struct json_object *json_object_new_stringf(const char *fmt, ...)
+{
+ struct json_object *ret;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = json_object_new_stringv(fmt, args);
+ va_end(args);
+
+ return ret;
+}
+
#define JSON_STR "JavaScript Object Notation\n"
/* NOTE: json-c lib has following commit 316da85 which
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
index 17695e6607..a139b9a14c 100644
--- a/lib/lib_errors.c
+++ b/lib/lib_errors.c
@@ -41,19 +41,19 @@ static struct log_ref ferr_lib_warn[] = {
{
.code = EC_LIB_LINUX_NS,
.title = "The Linux namespace subsystem has encountered a parsing error",
- .description = "During system startup an invalid parameter for the namesapce was give to FRR",
+ .description = "During system startup an invalid parameter for the namespace was give to FRR",
.suggestion = "Gather log data and open an Issue. restart FRR",
},
{
.code = EC_LIB_SLOW_THREAD_CPU,
.title = "The Event subsystem has detected a slow cpu time process",
- .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed",
+ .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination thereof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed",
.suggestion = "Gather log data and open an Issue",
},
{
.code = EC_LIB_SLOW_THREAD_WALL,
.title = "The Event subsystem has detected a slow wall time process",
- .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination therof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying",
+ .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination thereof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying",
.suggestion = "Gather log data and open an Issue",
},
{
@@ -286,7 +286,7 @@ static struct log_ref ferr_lib_err[] = {
},
{
.code = EC_LIB_NB_CB_INVALID_PRIO,
- .title = "Norhtbound callback has an invalid priority",
+ .title = "Northbound callback has an invalid priority",
.description = "The northbound subsystem, during initialization, has detected a callback whose priority is invalid",
.suggestion = "This is a bug; please report it"
},
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 9b05bb4fbf..1610ba4e7d 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -121,7 +121,6 @@ static const struct option lo_always[] = {
{"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR},
{"log", required_argument, NULL, OPTION_LOG},
{"log-level", required_argument, NULL, OPTION_LOGLEVEL},
- {"tcli", no_argument, NULL, OPTION_TCLI},
{"command-log-always", no_argument, NULL, OPTION_LOGGING},
{"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS},
{NULL}};
@@ -138,31 +137,43 @@ static const struct optspec os_always = {
" --scriptdir Override scripts directory\n"
" --log Set Logging to stdout, syslog, or file:<name>\n"
" --log-level Set Logging Level to use, debug, info, warn, etc\n"
- " --tcli Use transaction-based CLI\n"
" --limit-fds Limit number of fds supported\n",
lo_always};
-static const struct option lo_cfg_pid_dry[] = {
- {"pid_file", required_argument, NULL, 'i'},
+static const struct option lo_cfg[] = {
{"config_file", required_argument, NULL, 'f'},
-#ifdef HAVE_SQLITE3
- {"db_file", required_argument, NULL, OPTION_DB_FILE},
-#endif
{"dryrun", no_argument, NULL, 'C'},
- {"terminal", no_argument, NULL, 't'},
{NULL}};
-static const struct optspec os_cfg_pid_dry = {
- "f:i:Ct",
+static const struct optspec os_cfg = {
+ "f:C",
" -f, --config_file Set configuration file name\n"
- " -i, --pid_file Set process identifier file name\n"
+ " -C, --dryrun Check configuration for validity and exit\n",
+ lo_cfg};
+
+
+static const struct option lo_fullcli[] = {
+ {"terminal", no_argument, NULL, 't'},
+ {"tcli", no_argument, NULL, OPTION_TCLI},
#ifdef HAVE_SQLITE3
- " --db_file Set database file name\n"
+ {"db_file", required_argument, NULL, OPTION_DB_FILE},
#endif
- " -C, --dryrun Check configuration for validity and exit\n"
+ {NULL}};
+static const struct optspec os_fullcli = {
+ "t",
+ " --tcli Use transaction-based CLI\n"
" -t, --terminal Open terminal session on stdio\n"
" -d -t Daemonize after terminal session ends\n",
- lo_cfg_pid_dry};
+ lo_fullcli};
+
+
+static const struct option lo_pid[] = {
+ {"pid_file", required_argument, NULL, 'i'},
+ {NULL}};
+static const struct optspec os_pid = {
+ "i:",
+ " -i, --pid_file Set process identifier file name\n",
+ lo_pid};
static const struct option lo_zclient[] = {
@@ -320,8 +331,12 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
umask(0027);
opt_extend(&os_always);
- if (!(di->flags & FRR_NO_CFG_PID_DRY))
- opt_extend(&os_cfg_pid_dry);
+ if (!(di->flags & FRR_NO_SPLIT_CONFIG))
+ opt_extend(&os_cfg);
+ if (!(di->flags & FRR_LIMITED_CLI))
+ opt_extend(&os_fullcli);
+ if (!(di->flags & FRR_NO_PID))
+ opt_extend(&os_pid);
if (!(di->flags & FRR_NO_PRIVSEP))
opt_extend(&os_user);
if (!(di->flags & FRR_NO_ZCLIENT))
@@ -459,12 +474,12 @@ static int frr_opt(int opt)
frr_defaults_profile_set(optarg);
break;
case 'i':
- if (di->flags & FRR_NO_CFG_PID_DRY)
+ if (di->flags & FRR_NO_PID)
return 1;
di->pid_file = optarg;
break;
case 'f':
- if (di->flags & FRR_NO_CFG_PID_DRY)
+ if (di->flags & FRR_NO_SPLIT_CONFIG)
return 1;
di->config_file = optarg;
break;
@@ -497,18 +512,18 @@ static int frr_opt(int opt)
break;
#ifdef HAVE_SQLITE3
case OPTION_DB_FILE:
- if (di->flags & FRR_NO_CFG_PID_DRY)
+ if (di->flags & FRR_NO_PID)
return 1;
di->db_file = optarg;
break;
#endif
case 'C':
- if (di->flags & FRR_NO_CFG_PID_DRY)
+ if (di->flags & FRR_NO_SPLIT_CONFIG)
return 1;
di->dryrun = true;
break;
case 't':
- if (di->flags & FRR_NO_CFG_PID_DRY)
+ if (di->flags & FRR_LIMITED_CLI)
return 1;
di->terminal = true;
break;
@@ -986,7 +1001,7 @@ void frr_config_fork(void)
{
hook_call(frr_late_init, master);
- if (!(di->flags & FRR_NO_CFG_PID_DRY)) {
+ if (!(di->flags & FRR_NO_SPLIT_CONFIG)) {
/* Don't start execution if we are in dry-run mode */
if (di->dryrun) {
frr_config_read_in(NULL);
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 3dc5d7af81..e0642ef847 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -40,15 +40,17 @@ extern "C" {
#define FRR_NO_PRIVSEP (1 << 0)
#define FRR_NO_TCPVTY (1 << 1)
#define FRR_LIMITED_CLI (1 << 2)
-#define FRR_NO_CFG_PID_DRY (1 << 3)
-#define FRR_NO_ZCLIENT (1 << 4)
+#define FRR_NO_SPLIT_CONFIG (1 << 3)
+#define FRR_NO_PID (1 << 4)
+#define FRR_NO_CFG_PID_DRY (FRR_NO_PID | FRR_NO_SPLIT_CONFIG)
+#define FRR_NO_ZCLIENT (1 << 5)
/* If FRR_DETACH_LATER is used, the daemon will keep its parent running
* until frr_detach() is called. Normally "somedaemon -d" returns once the
* main event loop is reached in the daemon; use this for extra startup bits.
*
* Does nothing if -d isn't used.
*/
-#define FRR_DETACH_LATER (1 << 5)
+#define FRR_DETACH_LATER (1 << 6)
enum frr_cli_mode {
FRR_CLI_CLASSIC = 0,
@@ -94,7 +96,7 @@ struct frr_daemon_info {
const char *copyright;
char startinfo[128];
- struct quagga_signal_t *signals;
+ struct frr_signal_t *signals;
size_t n_signals;
struct zebra_privs_t *privs;
diff --git a/lib/libospf.h b/lib/libospf.h
index d2bb29d80e..c8ada9d3c5 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -36,7 +36,7 @@ extern "C" {
#define IPPROTO_OSPFIGP 89
#endif /* IPPROTO_OSPFIGP */
-/* Architectual Constants */
+/* Architectural Constants */
#ifdef DEBUG
#define OSPF_LS_REFRESH_TIME 120
#else
diff --git a/lib/link_state.c b/lib/link_state.c
index 062384aac7..b0bc386b79 100644
--- a/lib/link_state.c
+++ b/lib/link_state.c
@@ -46,6 +46,28 @@ DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database");
/**
* Link State Node management functions
*/
+int ls_node_id_same(struct ls_node_id i1, struct ls_node_id i2)
+{
+ if (i1.origin != i2.origin)
+ return 0;
+
+ if (i1.origin == UNKNOWN)
+ return 1;
+
+ if (i1.origin == ISIS_L1 || i1.origin == ISIS_L2) {
+ if (memcmp(i1.id.iso.sys_id, i2.id.iso.sys_id, ISO_SYS_ID_LEN)
+ != 0
+ || (i1.id.iso.level != i2.id.iso.level))
+ return 0;
+ } else {
+ if (!IPV4_ADDR_SAME(&i1.id.ip.addr, &i2.id.ip.addr)
+ || !IPV4_ADDR_SAME(&i1.id.ip.area_id, &i2.id.ip.area_id))
+ return 1;
+ }
+
+ return 1;
+}
+
struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid,
struct in6_addr rid6)
{
@@ -83,29 +105,56 @@ void ls_node_del(struct ls_node *node)
int ls_node_same(struct ls_node *n1, struct ls_node *n2)
{
+ /* First, check pointer */
if ((n1 && !n2) || (!n1 && n2))
return 0;
if (n1 == n2)
return 1;
+ /* Then, verify Flags and Origin */
if (n1->flags != n2->flags)
return 0;
- if (n1->adv.origin != n2->adv.origin)
+ if (!ls_node_id_same(n1->adv, n2->adv))
return 0;
- if (!memcmp(&n1->adv.id, &n2->adv.id, sizeof(struct ls_node_id)))
+ /* Finally, check each individual parameters that are valid */
+ if (CHECK_FLAG(n1->flags, LS_NODE_NAME)
+ && (strncmp(n1->name, n2->name, MAX_NAME_LENGTH) != 0))
return 0;
-
- /* Do we need to test individually each field, instead performing a
- * global memcmp? There is a risk that an old value that is bit masked
- * i.e. corresponding flag = 0, will result into a false negative
- */
- if (!memcmp(n1, n2, sizeof(struct ls_node)))
+ if (CHECK_FLAG(n1->flags, LS_NODE_ROUTER_ID)
+ && !IPV4_ADDR_SAME(&n1->router_id, &n2->router_id))
return 0;
- else
- return 1;
+ if (CHECK_FLAG(n1->flags, LS_NODE_ROUTER_ID6)
+ && !IPV6_ADDR_SAME(&n1->router6_id, &n2->router6_id))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_FLAG)
+ && (n1->node_flag != n2->node_flag))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_TYPE) && (n1->type != n2->type))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_AS_NUMBER)
+ && (n1->as_number != n2->as_number))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_SR)) {
+ if (n1->srgb.flag != n2->srgb.flag
+ || n1->srgb.lower_bound != n2->srgb.lower_bound
+ || n1->srgb.range_size != n2->srgb.range_size)
+ return 0;
+ if ((n1->algo[0] != n2->algo[0])
+ || (n1->algo[1] != n2->algo[1]))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_SRLB)
+ && ((n1->srlb.lower_bound != n2->srlb.lower_bound
+ || n1->srlb.range_size != n2->srlb.range_size)))
+ return 0;
+ if (CHECK_FLAG(n1->flags, LS_NODE_MSD) && (n1->msd != n2->msd))
+ return 0;
+ }
+
+ /* OK, n1 & n2 are equal */
+ return 1;
}
/**
@@ -171,29 +220,133 @@ void ls_attributes_del(struct ls_attributes *attr)
int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
{
+ /* First, check pointer */
if ((l1 && !l2) || (!l1 && l2))
return 0;
if (l1 == l2)
return 1;
+ /* Then, verify Flags and Origin */
if (l1->flags != l2->flags)
return 0;
- if (l1->adv.origin != l2->adv.origin)
+ if (!ls_node_id_same(l1->adv, l2->adv))
return 0;
- if (!memcmp(&l1->adv.id, &l2->adv.id, sizeof(struct ls_node_id)))
+ /* Finally, check each individual parameters that are valid */
+ if (CHECK_FLAG(l1->flags, LS_ATTR_NAME)
+ && strncmp(l1->name, l2->name, MAX_NAME_LENGTH) != 0)
return 0;
-
- /* Do we need to test individually each field, instead performing a
- * global memcmp? There is a risk that an old value that is bit masked
- * i.e. corresponding flag = 0, will result into a false negative
- */
- if (!memcmp(l1, l2, sizeof(struct ls_attributes)))
+ if (CHECK_FLAG(l1->flags, LS_ATTR_METRIC) && (l1->metric != l2->metric))
return 0;
- else
- return 1;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_TE_METRIC)
+ && (l1->standard.te_metric != l2->standard.te_metric))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_ADM_GRP)
+ && (l1->standard.admin_group != l2->standard.admin_group))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ADDR)
+ && !IPV4_ADDR_SAME(&l1->standard.local, &l2->standard.local))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ADDR)
+ && !IPV4_ADDR_SAME(&l1->standard.remote, &l2->standard.remote))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ADDR6)
+ && !IPV6_ADDR_SAME(&l1->standard.local6, &l2->standard.local6))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ADDR6)
+ && !IPV6_ADDR_SAME(&l1->standard.remote6, &l2->standard.remote6))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ID)
+ && (l1->standard.local_id != l2->standard.local_id))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ID)
+ && (l1->standard.remote_id != l2->standard.remote_id))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_MAX_BW)
+ && (l1->standard.max_bw != l2->standard.max_bw))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_MAX_RSV_BW)
+ && (l1->standard.max_rsv_bw != l2->standard.max_rsv_bw))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_UNRSV_BW)
+ && memcmp(&l1->standard.unrsv_bw, &l2->standard.unrsv_bw, 32) != 0)
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_AS)
+ && (l1->standard.remote_as != l2->standard.remote_as))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_ADDR)
+ && !IPV4_ADDR_SAME(&l1->standard.remote_addr,
+ &l2->standard.remote_addr))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_ADDR6)
+ && !IPV6_ADDR_SAME(&l1->standard.remote_addr6,
+ &l2->standard.remote_addr6))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_DELAY)
+ && (l1->extended.delay != l2->extended.delay))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_MIN_MAX_DELAY)
+ && ((l1->extended.min_delay != l2->extended.min_delay)
+ || (l1->extended.max_delay != l2->extended.max_delay)))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_JITTER)
+ && (l1->extended.jitter != l2->extended.jitter))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_PACKET_LOSS)
+ && (l1->extended.pkt_loss != l2->extended.pkt_loss))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_AVA_BW)
+ && (l1->extended.ava_bw != l2->extended.ava_bw))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_RSV_BW)
+ && (l1->extended.rsv_bw != l2->extended.rsv_bw))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_USE_BW)
+ && (l1->extended.used_bw != l2->extended.used_bw))
+ return 0;
+ if (CHECK_FLAG(l1->flags, LS_ATTR_ADJ_SID)) {
+ if ((l1->adj_sid[0].sid != l2->adj_sid[0].sid)
+ || (l1->adj_sid[0].flags != l2->adj_sid[0].flags)
+ || (l1->adj_sid[0].weight != l2->adj_sid[0].weight))
+ return 0;
+ if (((l1->adv.origin == ISIS_L1) || (l1->adv.origin == ISIS_L2))
+ && (memcmp(&l1->adj_sid[0].neighbor.sysid,
+ &l2->adj_sid[0].neighbor.sysid, ISO_SYS_ID_LEN)
+ != 0))
+ return 0;
+ if (((l1->adv.origin == OSPFv2) || (l1->adv.origin == STATIC)
+ || (l1->adv.origin == DIRECT))
+ && (!IPV4_ADDR_SAME(&l1->adj_sid[0].neighbor.addr,
+ &l2->adj_sid[0].neighbor.addr)))
+ return 0;
+ }
+ if (CHECK_FLAG(l1->flags, LS_ATTR_BCK_ADJ_SID)) {
+ if ((l1->adj_sid[1].sid != l2->adj_sid[1].sid)
+ || (l1->adj_sid[1].flags != l2->adj_sid[1].flags)
+ || (l1->adj_sid[1].weight != l2->adj_sid[1].weight))
+ return 0;
+ if (((l1->adv.origin == ISIS_L1) || (l1->adv.origin == ISIS_L2))
+ && (memcmp(&l1->adj_sid[1].neighbor.sysid,
+ &l2->adj_sid[1].neighbor.sysid, ISO_SYS_ID_LEN)
+ != 0))
+ return 0;
+ if (((l1->adv.origin == OSPFv2) || (l1->adv.origin == STATIC)
+ || (l1->adv.origin == DIRECT))
+ && (!IPV4_ADDR_SAME(&l1->adj_sid[1].neighbor.addr,
+ &l2->adj_sid[1].neighbor.addr)))
+ return 0;
+ }
+ if (CHECK_FLAG(l1->flags, LS_ATTR_SRLG)
+ && ((l1->srlg_len != l2->srlg_len)
+ || memcmp(l1->srlgs, l2->srlgs,
+ l1->srlg_len * sizeof(uint32_t))
+ != 0))
+ return 0;
+
+ /* OK, l1 & l2 are equal */
+ return 1;
}
/**
@@ -223,29 +376,42 @@ void ls_prefix_del(struct ls_prefix *pref)
int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2)
{
+ /* First, check pointer */
if ((p1 && !p2) || (!p1 && p2))
return 0;
if (p1 == p2)
return 1;
+ /* Then, verify Flags and Origin */
if (p1->flags != p2->flags)
return 0;
- if (p1->adv.origin != p2->adv.origin)
+ if (!ls_node_id_same(p1->adv, p2->adv))
return 0;
- if (!memcmp(&p1->adv.id, &p2->adv.id, sizeof(struct ls_node_id)))
+ /* Finally, check each individual parameters that are valid */
+ if (prefix_same(&p1->pref, &p2->pref) == 0)
return 0;
-
- /* Do we need to test individually each field, instead performing a
- * global memcmp? There is a risk that an old value that is bit masked
- * i.e. corresponding flag = 0, will result into a false negative
- */
- if (!memcmp(p1, p2, sizeof(struct ls_prefix)))
+ if (CHECK_FLAG(p1->flags, LS_PREF_IGP_FLAG)
+ && (p1->igp_flag != p2->igp_flag))
return 0;
- else
- return 1;
+ if (CHECK_FLAG(p1->flags, LS_PREF_ROUTE_TAG)
+ && (p1->route_tag != p2->route_tag))
+ return 0;
+ if (CHECK_FLAG(p1->flags, LS_PREF_EXTENDED_TAG)
+ && (p1->extended_tag != p2->extended_tag))
+ return 0;
+ if (CHECK_FLAG(p1->flags, LS_PREF_METRIC) && (p1->metric != p2->metric))
+ return 0;
+ if (CHECK_FLAG(p1->flags, LS_PREF_SR)) {
+ if ((p1->sr.algo != p2->sr.algo) || (p1->sr.sid != p2->sr.sid)
+ || (p1->sr.sid_flag != p2->sr.sid_flag))
+ return 0;
+ }
+
+ /* OK, p1 & p2 are equal */
+ return 1;
}
/**
@@ -844,11 +1010,11 @@ void ls_ted_del_all(struct ls_ted *ted)
return;
/* First remove Vertices, Edges and Subnets and associated Link State */
- frr_each (vertices, &ted->vertices, vertex)
+ frr_each_safe (vertices, &ted->vertices, vertex)
ls_vertex_del_all(ted, vertex);
- frr_each (edges, &ted->edges, edge)
+ frr_each_safe (edges, &ted->edges, edge)
ls_edge_del_all(ted, edge);
- frr_each (subnets, &ted->subnets, subnet)
+ frr_each_safe (subnets, &ted->subnets, subnet)
ls_subnet_del_all(ted, subnet);
/* then remove TED itself */
@@ -865,17 +1031,17 @@ void ls_ted_clean(struct ls_ted *ted)
return;
/* First, start with Vertices */
- frr_each (vertices, &ted->vertices, vertex)
+ frr_each_safe (vertices, &ted->vertices, vertex)
if (vertex->status == ORPHAN)
ls_vertex_del_all(ted, vertex);
/* Then Edges */
- frr_each (edges, &ted->edges, edge)
+ frr_each_safe (edges, &ted->edges, edge)
if (edge->status == ORPHAN)
ls_edge_del_all(ted, edge);
/* and Subnets */
- frr_each (subnets, &ted->subnets, subnet)
+ frr_each_safe (subnets, &ted->subnets, subnet)
if (subnet->status == ORPHAN)
ls_subnet_del_all(ted, subnet);
diff --git a/lib/link_state.h b/lib/link_state.h
index de116df89e..981e8b5285 100644
--- a/lib/link_state.h
+++ b/lib/link_state.h
@@ -94,6 +94,16 @@ struct ls_node_id {
} id __attribute__((aligned(8)));
};
+/**
+ * Check if two Link State Node IDs are equal. Note that this routine has the
+ * same return value sense as '==' (which is different from a comparison).
+ *
+ * @param i1 First Link State Node Identifier
+ * @param i2 Second Link State Node Identifier
+ * @return 1 if equal, 0 otherwise
+ */
+extern int ls_node_id_same(struct ls_node_id i1, struct ls_node_id i2);
+
/* Link State flags to indicate which Node parameters are valid */
#define LS_NODE_UNSET 0x0000
#define LS_NODE_NAME 0x0001
diff --git a/lib/log.c b/lib/log.c
index 936422104f..fb12c08aae 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -64,7 +64,7 @@ const char *lookup_msg(const struct message *mz, int kz, const char *nf)
}
/* For time string format. */
-size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
+size_t frr_timestamp(int timestamp_precision, char *buf, size_t buflen)
{
static struct {
time_t last;
@@ -355,9 +355,6 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_ADD),
DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE),
DESC_ENTRY(ZEBRA_INTERFACE_BFD_DEST_UPDATE),
- DESC_ENTRY(ZEBRA_IMPORT_ROUTE_REGISTER),
- DESC_ENTRY(ZEBRA_IMPORT_ROUTE_UNREGISTER),
- DESC_ENTRY(ZEBRA_IMPORT_CHECK_UPDATE),
DESC_ENTRY(ZEBRA_BFD_DEST_REGISTER),
DESC_ENTRY(ZEBRA_BFD_DEST_DEREGISTER),
DESC_ENTRY(ZEBRA_BFD_DEST_UPDATE),
diff --git a/lib/log.h b/lib/log.h
index 59f1742d01..3011fa9a99 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -102,9 +102,9 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter);
It caches the most recent localtime result and can therefore
avoid multiple calls within the same second. If buflen is too small,
*buf will be set to '\0', and 0 will be returned. */
-#define QUAGGA_TIMESTAMP_LEN 40
-extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */,
- char *buf, size_t buflen);
+#define FRR_TIMESTAMP_LEN 40
+extern size_t frr_timestamp(int timestamp_precision /* # subsecond digits */,
+ char *buf, size_t buflen);
extern void zlog_hexdump(const void *mem, size_t len);
extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in,
@@ -135,8 +135,8 @@ struct timestamp_control {
size_t len; /* length of rendered timestamp */
int precision; /* configuration parameter */
int already_rendered; /* should be initialized to 0 */
- char buf[QUAGGA_TIMESTAMP_LEN]; /* will contain the rendered timestamp
- */
+ char buf[FRR_TIMESTAMP_LEN]; /* will contain the rendered timestamp
+ */
};
/* Defines for use in command construction: */
diff --git a/lib/log_vty.c b/lib/log_vty.c
index cbb8de8976..621949ab57 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -36,6 +36,8 @@
DEFINE_HOOK(zlog_rotate, (), ());
DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
+static unsigned logmsgs_with_persist_bt;
+
static const int log_default_lvl = LOG_DEBUG;
static int log_config_stdout_lvl = ZLOG_DISABLED;
@@ -267,6 +269,43 @@ DEFUN_HIDDEN (no_config_log_monitor,
return CMD_SUCCESS;
}
+DEFPY_NOSH (debug_uid_backtrace,
+ debug_uid_backtrace_cmd,
+ "[no] debug unique-id UID backtrace",
+ NO_STR
+ DEBUG_STR
+ "Options per individual log message, by unique ID\n"
+ "Log message unique ID (XXXXX-XXXXX)\n"
+ "Add backtrace to log when message is printed\n")
+{
+ struct xrefdata search, *xrd;
+ struct xrefdata_logmsg *xrdl;
+ uint8_t flag;
+
+ strlcpy(search.uid, uid, sizeof(search.uid));
+ xrd = xrefdata_uid_find(&xrefdata_uid, &search);
+
+ if (!xrd)
+ return CMD_ERR_NOTHING_TODO;
+
+ if (xrd->xref->type != XREFT_LOGMSG) {
+ vty_out(vty, "%% ID \"%s\" is not a log message\n", uid);
+ return CMD_WARNING;
+ }
+ xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata);
+
+ flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT
+ : LOGMSG_FLAG_EPHEMERAL;
+
+ if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag))
+ return CMD_SUCCESS;
+ if (flag == LOGMSG_FLAG_PERSISTENT)
+ logmsgs_with_persist_bt += no ? -1 : 1;
+
+ xrdl->fl_print_bt ^= flag;
+ return CMD_SUCCESS;
+}
+
static int set_log_file(struct zlog_cfg_file *target, struct vty *vty,
const char *fname, int loglevel)
{
@@ -751,6 +790,24 @@ void log_config_write(struct vty *vty)
vty_out(vty, "no log error-category\n");
if (!zlog_get_prefix_xid())
vty_out(vty, "no log unique-id\n");
+
+ if (logmsgs_with_persist_bt) {
+ struct xrefdata *xrd;
+ struct xrefdata_logmsg *xrdl;
+
+ vty_out(vty, "!\n");
+
+ frr_each (xrefdata_uid, &xrefdata_uid, xrd) {
+ if (xrd->xref->type != XREFT_LOGMSG)
+ continue;
+
+ xrdl = container_of(xrd, struct xrefdata_logmsg,
+ xrefdata);
+ if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT)
+ vty_out(vty, "debug unique-id %s backtrace\n",
+ xrd->uid);
+ }
+ }
}
static int log_vty_init(const char *progname, const char *protoname,
@@ -801,4 +858,7 @@ void log_cmd_init(void)
install_element(CONFIG_NODE, &config_log_filterfile_cmd);
install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
install_element(CONFIG_NODE, &log_immediate_mode_cmd);
+
+ install_element(ENABLE_NODE, &debug_uid_backtrace_cmd);
+ install_element(CONFIG_NODE, &debug_uid_backtrace_cmd);
}
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index cde842b88c..43c0d8c359 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -279,7 +279,7 @@ static void ns_disable_internal(struct ns *ns)
}
}
-/* VRF list existance check by name. */
+/* VRF list existence check by name. */
static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id)
{
struct ns_map_nsid ns_map;
diff --git a/lib/network.h b/lib/network.h
index 4a9666984f..10ed917572 100644
--- a/lib/network.h
+++ b/lib/network.h
@@ -22,6 +22,13 @@
#ifndef _ZEBRA_NETWORK_H
#define _ZEBRA_NETWORK_H
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#endif
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -45,6 +52,35 @@ extern int set_cloexec(int fd);
extern float htonf(float);
extern float ntohf(float);
+/* force type for be64toh/htobe64 to be uint64_t, *without* a direct cast
+ *
+ * this is a workaround for false-positive printfrr warnings from FRR's
+ * frr-format GCC plugin that would be triggered from
+ * { printfrr("%"PRIu64, (uint64_t)be64toh(...)); }
+ *
+ * the key element here is that "(uint64_t)expr" causes the warning, while
+ * "({ uint64_t x = expr; x; })" does not. (The cast is the trigger, a
+ * variable of the same type works correctly.)
+ */
+
+/* zap system definitions... */
+#ifdef be64toh
+#undef be64toh
+#endif
+#ifdef htobe64
+#undef htobe64
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define be64toh(x) ({ uint64_t r = __builtin_bswap64(x); r; })
+#define htobe64(x) ({ uint64_t r = __builtin_bswap64(x); r; })
+#elif BYTE_ORDER == BIG_ENDIAN
+#define be64toh(x) ({ uint64_t r = (x); r; })
+#define htobe64(x) ({ uint64_t r = (x); r; })
+#else
+#error nobody expects the endianish inquisition. check OS endian.h headers.
+#endif
+
/**
* Helper function that returns a random long value. The main purpose of
* this function is to hide a `random()` call that gets flagged by coverity
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 97d70189ff..e8c678ad71 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -953,12 +953,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
nhg_hooks.add_nexthop(nhgc, nh);
}
- if (intf) {
- struct interface *ifp = if_lookup_by_name_all_vrf(intf);
-
- if (ifp)
- ifp->configured = true;
- }
return CMD_SUCCESS;
}
@@ -1041,7 +1035,6 @@ void nexthop_group_write_nexthop(struct vty *vty, const 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;
@@ -1052,26 +1045,18 @@ void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh)
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
case NEXTHOP_TYPE_IPV4:
- json_object_string_add(
- j, "nexthop",
- inet_ntop(AF_INET, &nh->gate.ipv4, buf, sizeof(buf)));
+ json_object_string_addf(j, "nexthop", "%pI4", &nh->gate.ipv4);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- json_object_string_add(
- j, "nexthop",
- inet_ntop(AF_INET, &nh->gate.ipv4, buf, sizeof(buf)));
+ json_object_string_addf(j, "nexthop", "%pI4", &nh->gate.ipv4);
json_object_string_add(j, "vrfId",
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
case NEXTHOP_TYPE_IPV6:
- json_object_string_add(
- j, "nexthop",
- inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
+ json_object_string_addf(j, "nexthop", "%pI6", &nh->gate.ipv6);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
- json_object_string_add(
- j, "nexthop",
- inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
+ json_object_string_addf(j, "nexthop", "%pI6", &nh->gate.ipv6);
json_object_string_add(j, "vrfId",
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
@@ -1265,7 +1250,6 @@ void nexthop_group_interface_state_change(struct interface *ifp,
if (ifp->ifindex != nhop.ifindex)
continue;
- ifp->configured = true;
nh = nexthop_new();
memcpy(nh, &nhop, sizeof(nhop));
diff --git a/lib/northbound.c b/lib/northbound.c
index 6edd5184ef..49adea6d53 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -830,8 +830,7 @@ int nb_candidate_validate(struct nb_context *context,
struct nb_config_cbs changes;
int ret;
- if (nb_candidate_validate_yang(candidate, errmsg, sizeof(errmsg_len))
- != NB_OK)
+ if (nb_candidate_validate_yang(candidate, errmsg, errmsg_len) != NB_OK)
return NB_ERR_VALIDATION;
RB_INIT(nb_config_cbs, &changes);
diff --git a/lib/northbound.h b/lib/northbound.h
index bf04dbda17..a330bd1a30 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -488,7 +488,8 @@ struct nb_callbacks {
* >0 when the CLI command for the dnode2 should be printed first
* 0 when there is no difference
*/
- int (*cli_cmp)(struct lyd_node *dnode1, struct lyd_node *dnode2);
+ int (*cli_cmp)(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
/*
* Optional callback to show the CLI command associated to the given
@@ -510,7 +511,7 @@ struct nb_callbacks {
* nodes, in which case it might be desirable to hide one or more
* parts of the command when this parameter is set to false.
*/
- void (*cli_show)(struct vty *vty, struct lyd_node *dnode,
+ void (*cli_show)(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
/*
@@ -523,7 +524,7 @@ struct nb_callbacks {
* libyang data node that should be shown in the form of a CLI
* command.
*/
- void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode);
+ void (*cli_show_end)(struct vty *vty, const struct lyd_node *dnode);
};
struct nb_dependency_callbacks {
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 6676c0b072..70c71b18c4 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -550,14 +550,16 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
LYD_VALIDATE_NO_STATE, NULL);
}
-static int lyd_node_cmp(struct lyd_node **dnode1, struct lyd_node **dnode2)
+static int lyd_node_cmp(const struct lyd_node **dnode1,
+ const struct lyd_node **dnode2)
{
struct nb_node *nb_node = (*dnode1)->schema->priv;
return nb_node->cbs.cli_cmp(*dnode1, *dnode2);
}
-static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
+static void show_dnode_children_cmds(struct vty *vty,
+ const struct lyd_node *root,
bool with_defaults)
{
struct nb_node *nb_node, *sort_node = NULL;
@@ -616,7 +618,7 @@ static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
}
}
-void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
+void nb_cli_show_dnode_cmds(struct vty *vty, const struct lyd_node *root,
bool with_defaults)
{
struct nb_node *nb_node;
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index 28f81f8b39..e472425447 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -127,7 +127,8 @@ extern int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input,
* show_defaults
* Specify whether to display default configuration values or not.
*/
-extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode,
+extern void nb_cli_show_dnode_cmds(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
/*
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index e62a83cee2..e1c8983fca 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -491,6 +491,47 @@ static void *thread_cdb_trigger_subscriptions(void *data)
return NULL;
}
+static int frr_confd_subscribe(const struct lysc_node *snode, void *arg)
+{
+ struct yang_module *module = arg;
+ struct nb_node *nb_node;
+ int *spoint;
+ int ret;
+
+ switch (snode->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ break;
+ default:
+ return YANG_ITER_CONTINUE;
+ }
+
+ if (CHECK_FLAG(snode->flags, LYS_CONFIG_R))
+ return YANG_ITER_CONTINUE;
+
+ nb_node = snode->priv;
+ if (!nb_node)
+ return YANG_ITER_CONTINUE;
+
+ DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'", __func__,
+ nb_node->xpath);
+
+ spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint));
+ ret = cdb_subscribe2(cdb_sub_sock, CDB_SUB_RUNNING_TWOPHASE,
+ CDB_SUB_WANT_ABORT_ON_ABORT, 3, spoint,
+ module->confd_hash, nb_node->xpath);
+ if (ret != CONFD_OK) {
+ flog_err_confd("cdb_subscribe2");
+ XFREE(MTYPE_CONFD, spoint);
+ return YANG_ITER_CONTINUE;
+ }
+
+ listnode_add(confd_spoints, spoint);
+ return YANG_ITER_CONTINUE;
+}
+
static int frr_confd_init_cdb(void)
{
struct yang_module *module;
@@ -514,8 +555,6 @@ static int frr_confd_init_cdb(void)
/* Subscribe to all loaded YANG data modules. */
confd_spoints = list_new();
RB_FOREACH (module, yang_modules, &yang_modules) {
- struct lysc_node *snode;
-
module->confd_hash = confd_str2hash(module->info->ns);
if (module->confd_hash == 0) {
flog_err(
@@ -530,42 +569,8 @@ static int frr_confd_init_cdb(void)
* entire YANG module. So we have to find the top level
* nodes ourselves and subscribe to their paths.
*/
- LY_LIST_FOR (module->info->data, snode) {
- struct nb_node *nb_node;
- int *spoint;
- int ret;
-
- switch (snode->nodetype) {
- case LYS_CONTAINER:
- case LYS_LEAF:
- case LYS_LEAFLIST:
- case LYS_LIST:
- break;
- default:
- continue;
- }
-
- if (CHECK_FLAG(snode->flags, LYS_CONFIG_R))
- continue;
-
- nb_node = snode->priv;
- if (!nb_node)
- continue;
-
- DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'",
- __func__, nb_node->xpath);
-
- spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint));
- ret = cdb_subscribe2(
- cdb_sub_sock, CDB_SUB_RUNNING_TWOPHASE,
- CDB_SUB_WANT_ABORT_ON_ABORT, 3, spoint,
- module->confd_hash, nb_node->xpath);
- if (ret != CONFD_OK) {
- flog_err_confd("cdb_subscribe2");
- XFREE(MTYPE_CONFD, spoint);
- }
- listnode_add(confd_spoints, spoint);
- }
+ yang_snodes_iterate(module->info, frr_confd_subscribe, 0,
+ module);
}
if (cdb_subscribe_done(cdb_sub_sock) != CONFD_OK) {
@@ -705,7 +710,7 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx,
confd_data_reply_next_key(tctx, v, keys.num,
(long)nb_next);
} else {
- char pointer_str[16];
+ char pointer_str[32];
/*
* ConfD 6.6 user guide, chapter 6.11 (Operational data
@@ -843,7 +848,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
const void *nb_next;
#define CONFD_OBJECTS_PER_TIME 100
struct confd_next_object objects[CONFD_OBJECTS_PER_TIME + 1];
- char pseudo_keys[CONFD_OBJECTS_PER_TIME][16];
+ char pseudo_keys[CONFD_OBJECTS_PER_TIME][32];
int nobjects = 0;
frr_confd_get_xpath(kp, xpath, sizeof(xpath));
@@ -868,7 +873,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx,
memset(objects, 0, sizeof(objects));
for (int j = 0; j < CONFD_OBJECTS_PER_TIME; j++) {
struct confd_next_object *object;
- struct lysc_node *child;
+ const struct lysc_node *child;
struct yang_data *data;
size_t nvalues = 0;
@@ -1189,6 +1194,8 @@ static int frr_confd_dp_ctl_read(struct thread *thread)
thread_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl);
frr_confd_dp_read(dctx, fd);
+
+ return 0;
}
static int frr_confd_dp_worker_read(struct thread *thread)
@@ -1199,6 +1206,8 @@ static int frr_confd_dp_worker_read(struct thread *thread)
thread_add_read(master, frr_confd_dp_worker_read, dctx, fd, &t_dp_worker);
frr_confd_dp_read(dctx, fd);
+
+ return 0;
}
static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg)
diff --git a/lib/pbr.h b/lib/pbr.h
index cef1d9d380..b14ba07503 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -50,7 +50,7 @@ struct pbr_filter {
#define PBR_FILTER_SRC_PORT_RANGE (1 << 6)
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
#define PBR_FILTER_DSFIELD (1 << 8)
-#define PBR_FILTER_IP_PROTOCOL (1 << 9)
+#define PBR_FILTER_IP_PROTOCOL (1 << 9)
#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
@@ -83,6 +83,13 @@ struct pbr_filter {
* the user criteria may directly point to a table too.
*/
struct pbr_action {
+ /* VLAN */
+ uint8_t pcp;
+ uint16_t vlan_id;
+ uint16_t vlan_flags;
+
+ uint32_t queue_id;
+
uint32_t table;
};
diff --git a/lib/plist.c b/lib/plist.c
index 2f9f06f43b..d6a63c1b0c 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -1010,7 +1010,6 @@ static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi,
if (json) {
json_object *json_entry;
- char buf[BUFSIZ];
json_entry = json_object_new_object();
json_object_array_add(json_entries, json_entry);
@@ -1021,10 +1020,9 @@ static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi,
json_object_string_add(
json_entry, "type",
prefix_list_type_str(pentry));
- json_object_string_add(
- json_entry, "prefix",
- prefix2str(&pentry->prefix, buf,
- sizeof(buf)));
+ json_object_string_addf(json_entry, "prefix",
+ "%pFX",
+ &pentry->prefix);
if (pentry->ge)
json_object_int_add(
@@ -1127,14 +1125,7 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name,
master, dtype, seqnum);
}
- if (uj) {
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
-
- return CMD_SUCCESS;
+ return vty_json(vty, json);
}
static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi,
@@ -1489,9 +1480,9 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp,
struct prefix_list_entry *pentry;
/* ge and le value check */
- if (orfp->ge && orfp->ge <= orfp->p.prefixlen)
+ if (orfp->ge && orfp->ge < orfp->p.prefixlen)
return CMD_WARNING_CONFIG_FAILED;
- if (orfp->le && orfp->le <= orfp->p.prefixlen)
+ if (orfp->le && orfp->le < orfp->p.prefixlen)
return CMD_WARNING_CONFIG_FAILED;
if (orfp->le && orfp->ge > orfp->le)
return CMD_WARNING_CONFIG_FAILED;
@@ -1592,9 +1583,7 @@ int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
json_object_object_add(json, "ipv6PrefixList",
json_prefix);
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
+ vty_json(vty, json);
} else {
vty_out(vty, "ip%s prefix-list %s: %d entries\n",
afi == AFI_IP ? "" : "v6", plist->name, plist->count);
@@ -1668,6 +1657,8 @@ static const struct cmd_variable_handler plist_var_handlers[] = {
{/* "prefix-list WORD" */
.varname = "prefix_list",
.completions = plist_autocomplete},
+ {.tokenname = "PREFIXLIST_NAME",
+ .completions = plist_autocomplete},
{.completions = NULL}};
diff --git a/lib/prefix.c b/lib/prefix.c
index ef7d2e59da..df753fe10b 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -113,7 +113,7 @@ const char *family2str(int family)
return "?";
}
-/* Address Famiy Identifier to Address Family converter. */
+/* Address Family Identifier to Address Family converter. */
int afi2family(afi_t afi)
{
if (afi == AFI_IP)
diff --git a/lib/resolver.c b/lib/resolver.c
index 4aba909f25..29138bbc8d 100644
--- a/lib/resolver.c
+++ b/lib/resolver.c
@@ -14,12 +14,14 @@
#include <ares.h>
#include <ares_version.h>
-#include "vector.h"
+#include "typesafe.h"
+#include "jhash.h"
#include "thread.h"
#include "lib_errors.h"
#include "resolver.h"
#include "command.h"
#include "xref.h"
+#include "vrf.h"
XREF_SETUP();
@@ -27,13 +29,78 @@ struct resolver_state {
ares_channel channel;
struct thread_master *master;
struct thread *timeout;
- vector read_threads, write_threads;
};
static struct resolver_state state;
static bool resolver_debug;
-#define THREAD_RUNNING ((struct thread *)-1)
+/* a FD doesn't necessarily map 1:1 to a request; we could be talking to
+ * multiple caches simultaneously, to see which responds fastest.
+ * Theoretically we could also be using the same fd for multiple lookups,
+ * but the c-ares API guarantees an n:1 mapping for fd => channel.
+ *
+ * Either way c-ares makes that decision and we just need to deal with
+ * whatever FDs it gives us.
+ */
+
+DEFINE_MTYPE_STATIC(LIB, ARES_FD, "c-ares (DNS) file descriptor information");
+PREDECL_HASH(resolver_fds);
+
+struct resolver_fd {
+ struct resolver_fds_item itm;
+
+ int fd;
+ struct resolver_state *state;
+ struct thread *t_read, *t_write;
+};
+
+static int resolver_fd_cmp(const struct resolver_fd *a,
+ const struct resolver_fd *b)
+{
+ return numcmp(a->fd, b->fd);
+}
+
+static uint32_t resolver_fd_hash(const struct resolver_fd *item)
+{
+ return jhash_1word(item->fd, 0xacd04c9e);
+}
+
+DECLARE_HASH(resolver_fds, struct resolver_fd, itm, resolver_fd_cmp,
+ resolver_fd_hash);
+
+static struct resolver_fds_head resfds[1] = {INIT_HASH(resfds[0])};
+
+static struct resolver_fd *resolver_fd_get(int fd,
+ struct resolver_state *newstate)
+{
+ struct resolver_fd ref = {.fd = fd}, *res;
+
+ res = resolver_fds_find(resfds, &ref);
+ if (!res && newstate) {
+ res = XCALLOC(MTYPE_ARES_FD, sizeof(*res));
+ res->fd = fd;
+ res->state = newstate;
+ resolver_fds_add(resfds, res);
+
+ if (resolver_debug)
+ zlog_debug("c-ares registered FD %d", fd);
+ }
+ return res;
+}
+
+static void resolver_fd_drop_maybe(struct resolver_fd *resfd)
+{
+ if (resfd->t_read || resfd->t_write)
+ return;
+
+ if (resolver_debug)
+ zlog_debug("c-ares unregistered FD %d", resfd->fd);
+
+ resolver_fds_del(resfds, resfd);
+ XFREE(MTYPE_ARES_FD, resfd);
+}
+
+/* end of FD housekeeping */
static void resolver_update_timeouts(struct resolver_state *r);
@@ -41,9 +108,7 @@ static int resolver_cb_timeout(struct thread *t)
{
struct resolver_state *r = THREAD_ARG(t);
- r->timeout = THREAD_RUNNING;
ares_process(r->channel, NULL, NULL);
- r->timeout = NULL;
resolver_update_timeouts(r);
return 0;
@@ -51,17 +116,16 @@ static int resolver_cb_timeout(struct thread *t)
static int resolver_cb_socket_readable(struct thread *t)
{
- struct resolver_state *r = THREAD_ARG(t);
- int fd = THREAD_FD(t);
- struct thread **t_ptr;
-
- vector_set_index(r->read_threads, fd, THREAD_RUNNING);
- ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
- if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
- t_ptr = (struct thread **)vector_get_index(r->read_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_readable, r, fd,
- t_ptr);
- }
+ struct resolver_fd *resfd = THREAD_ARG(t);
+ struct resolver_state *r = resfd->state;
+
+ thread_add_read(r->master, resolver_cb_socket_readable, resfd,
+ resfd->fd, &resfd->t_read);
+ /* ^ ordering important:
+ * ares_process_fd may transitively call THREAD_OFF(resfd->t_read)
+ * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
+ */
+ ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD);
resolver_update_timeouts(r);
return 0;
@@ -69,17 +133,16 @@ static int resolver_cb_socket_readable(struct thread *t)
static int resolver_cb_socket_writable(struct thread *t)
{
- struct resolver_state *r = THREAD_ARG(t);
- int fd = THREAD_FD(t);
- struct thread **t_ptr;
-
- vector_set_index(r->write_threads, fd, THREAD_RUNNING);
- ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
- if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
- t_ptr = (struct thread **)vector_get_index(r->write_threads, fd);
- thread_add_write(r->master, resolver_cb_socket_writable, r, fd,
- t_ptr);
- }
+ struct resolver_fd *resfd = THREAD_ARG(t);
+ struct resolver_state *r = resfd->state;
+
+ thread_add_write(r->master, resolver_cb_socket_writable, resfd,
+ resfd->fd, &resfd->t_write);
+ /* ^ ordering important:
+ * ares_process_fd may transitively call THREAD_OFF(resfd->t_write)
+ * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
+ */
+ ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd);
resolver_update_timeouts(r);
return 0;
@@ -89,13 +152,11 @@ static void resolver_update_timeouts(struct resolver_state *r)
{
struct timeval *tv, tvbuf;
- if (r->timeout == THREAD_RUNNING)
- return;
-
THREAD_OFF(r->timeout);
tv = ares_timeout(r->channel, NULL, &tvbuf);
if (tv) {
unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+
thread_add_timer_msec(r->master, resolver_cb_timeout, r,
timeoutms, &r->timeout);
}
@@ -105,43 +166,27 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
int writable)
{
struct resolver_state *r = (struct resolver_state *)data;
- struct thread *t, **t_ptr;
-
- if (readable) {
- t = vector_lookup(r->read_threads, fd);
- if (!t) {
- t_ptr = (struct thread **)vector_get_index(
- r->read_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_readable,
- r, fd, t_ptr);
- }
- } else {
- t = vector_lookup(r->read_threads, fd);
- if (t) {
- if (t != THREAD_RUNNING) {
- THREAD_OFF(t);
- }
- vector_unset(r->read_threads, fd);
- }
- }
+ struct resolver_fd *resfd;
- if (writable) {
- t = vector_lookup(r->write_threads, fd);
- if (!t) {
- t_ptr = (struct thread **)vector_get_index(
- r->write_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_writable,
- r, fd, t_ptr);
- }
- } else {
- t = vector_lookup(r->write_threads, fd);
- if (t) {
- if (t != THREAD_RUNNING) {
- THREAD_OFF(t);
- }
- vector_unset(r->write_threads, fd);
- }
- }
+ resfd = resolver_fd_get(fd, (readable || writable) ? r : NULL);
+ if (!resfd)
+ return;
+
+ assert(resfd->state == r);
+
+ if (!readable)
+ THREAD_OFF(resfd->t_read);
+ else if (!resfd->t_read)
+ thread_add_read(r->master, resolver_cb_socket_readable, resfd,
+ fd, &resfd->t_read);
+
+ if (!writable)
+ THREAD_OFF(resfd->t_write);
+ else if (!resfd->t_write)
+ thread_add_write(r->master, resolver_cb_socket_writable, resfd,
+ fd, &resfd->t_write);
+
+ resolver_fd_drop_maybe(resfd);
}
@@ -200,7 +245,7 @@ static int resolver_cb_literal(struct thread *t)
return 0;
}
-void resolver_resolve(struct resolver_query *query, int af,
+void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id,
const char *hostname,
void (*callback)(struct resolver_query *, const char *,
int, union sockunion *))
@@ -235,7 +280,18 @@ void resolver_resolve(struct resolver_query *query, int af,
if (resolver_debug)
zlog_debug("[%p] Resolving '%s'", query, hostname);
+ ret = vrf_switch_to_netns(vrf_id);
+ if (ret < 0) {
+ flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
+ return;
+ }
ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
+ ret = vrf_switchback_to_initial();
+ if (ret < 0)
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
resolver_update_timeouts(&state);
}
@@ -271,8 +327,6 @@ void resolver_init(struct thread_master *tm)
struct ares_options ares_opts;
state.master = tm;
- state.read_threads = vector_init(1);
- state.write_threads = vector_init(1);
ares_opts = (struct ares_options){
.sock_state_cb = &ares_socket_cb,
diff --git a/lib/resolver.h b/lib/resolver.h
index 5f922dcb57..988449693c 100644
--- a/lib/resolver.h
+++ b/lib/resolver.h
@@ -27,10 +27,10 @@ struct resolver_query {
};
void resolver_init(struct thread_master *tm);
-void resolver_resolve(struct resolver_query *query, int af,
- const char *hostname, void (*cb)(struct resolver_query *,
- const char *, int,
- union sockunion *));
+void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id,
+ const char *hostname,
+ void (*cb)(struct resolver_query *, const char *, int,
+ union sockunion *));
#ifdef __cplusplus
}
diff --git a/lib/route_opaque.h b/lib/route_opaque.h
index 7c4e9a16e1..c5e7d6a327 100644
--- a/lib/route_opaque.h
+++ b/lib/route_opaque.h
@@ -36,6 +36,12 @@ struct bgp_zebra_opaque {
/* Show at least 10 large-communities AA:BB:CC */
char lcommunity[LCOMMUNITY_SIZE * 30];
+
+ /* 32 bytes seems enough because of
+ * bgp_path_selection_confed_as_path which is
+ * `Confederation based AS Path`.
+ */
+ char selection_reason[BGP_MAX_SELECTION_REASON_STR_BUF];
};
static_assert(sizeof(struct bgp_zebra_opaque) <= ZAPI_MESSAGE_OPAQUE_LENGTH,
diff --git a/lib/routemap.c b/lib/routemap.c
index 5c60b7d1c6..7f733c8114 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -34,6 +34,7 @@
#include "lib_errors.h"
#include "table.h"
#include "json.h"
+#include "jhash.h"
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
@@ -47,6 +48,27 @@ DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
DEFINE_QOBJ_TYPE(route_map_index);
DEFINE_QOBJ_TYPE(route_map);
+static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy *a,
+ const struct route_map_rule_cmd_proxy *b)
+{
+ return strcmp(a->cmd->str, b->cmd->str);
+}
+
+static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy *item)
+{
+ return jhash(item->cmd->str, strlen(item->cmd->str), 0xbfd69320);
+}
+
+DECLARE_HASH(rmap_cmd_name, struct route_map_rule_cmd_proxy, itm,
+ rmap_cmd_name_cmp, rmap_cmd_name_hash);
+
+static struct rmap_cmd_name_head rmap_match_cmds[1] = {
+ INIT_HASH(rmap_match_cmds[0]),
+};
+static struct rmap_cmd_name_head rmap_set_cmds[1] = {
+ INIT_HASH(rmap_set_cmds[0]),
+};
+
#define IPv4_PREFIX_LIST "ip address prefix-list"
#define IPv6_PREFIX_LIST "ipv6 address prefix-list"
@@ -61,12 +83,6 @@ struct route_map_pentry_dep {
route_map_event_t event;
};
-/* Vector for route match rules. */
-static vector route_match_vec;
-
-/* Vector for route set rules. */
-static vector route_set_vec;
-
static void route_map_pfx_tbl_update(route_map_event_t event,
struct route_map_index *index, afi_t afi,
const char *plist_name);
@@ -159,6 +175,22 @@ void route_map_no_match_ip_next_hop_hook(int (*func)(
rmap_match_set_hook.no_match_ip_next_hop = func;
}
+/* match ipv6 next-hop */
+void route_map_match_ipv6_next_hop_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+ rmap_match_set_hook.match_ipv6_next_hop = func;
+}
+
+/* no match ipv6 next-hop */
+void route_map_no_match_ipv6_next_hop_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+ rmap_match_set_hook.no_match_ipv6_next_hop = func;
+}
+
/* match ip next hop prefix list */
void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
struct route_map_index *index, const char *command,
@@ -250,6 +282,22 @@ void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
rmap_match_set_hook.no_match_ipv6_next_hop_type = func;
}
+/* match ipv6 next-hop prefix-list */
+void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+ rmap_match_set_hook.match_ipv6_next_hop_prefix_list = func;
+}
+
+/* no match ipv6 next-hop prefix-list */
+void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+ rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list = func;
+}
+
/* match metric */
void route_map_match_metric_hook(int (*func)(
struct route_map_index *index, const char *command,
@@ -1026,14 +1074,7 @@ static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
list_delete(&maplist);
}
- if (use_json) {
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
-
- return CMD_SUCCESS;
+ return vty_json(vty, json);
}
/* Unused route map details */
@@ -1231,40 +1272,40 @@ static struct route_map_rule *route_map_rule_new(void)
}
/* Install rule command to the match list. */
-void route_map_install_match(const struct route_map_rule_cmd *cmd)
+void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy)
{
- vector_set(route_match_vec, (void *)cmd);
+ rmap_cmd_name_add(rmap_match_cmds, proxy);
}
/* Install rule command to the set list. */
-void route_map_install_set(const struct route_map_rule_cmd *cmd)
+void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy)
{
- vector_set(route_set_vec, (void *)cmd);
+ rmap_cmd_name_add(rmap_set_cmds, proxy);
}
/* Lookup rule command from match list. */
static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
{
- unsigned int i;
- const struct route_map_rule_cmd *rule;
+ struct route_map_rule_cmd refcmd = {.str = name};
+ struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
+ struct route_map_rule_cmd_proxy *res;
- for (i = 0; i < vector_active(route_match_vec); i++)
- if ((rule = vector_slot(route_match_vec, i)) != NULL)
- if (strcmp(rule->str, name) == 0)
- return rule;
+ res = rmap_cmd_name_find(rmap_match_cmds, &ref);
+ if (res)
+ return res->cmd;
return NULL;
}
/* Lookup rule command from set list. */
static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
{
- unsigned int i;
- const struct route_map_rule_cmd *rule;
+ struct route_map_rule_cmd refcmd = {.str = name};
+ struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd};
+ struct route_map_rule_cmd_proxy *res;
- for (i = 0; i < vector_active(route_set_vec); i++)
- if ((rule = vector_slot(route_set_vec, i)) != NULL)
- if (strcmp(rule->str, name) == 0)
- return rule;
+ res = rmap_cmd_name_find(rmap_set_cmds, &ref);
+ if (res)
+ return res->cmd;
return NULL;
}
@@ -2480,7 +2521,7 @@ void route_map_notify_pentry_dependencies(const char *affected_name,
do whatever the exit policy (EXIT, NEXT or GOTO) tells.
on-match next - If this clause is matched, then the set statements
are executed and then we drop through to the next clause
- on-match goto n - If this clause is matched, then the set statments
+ on-match goto n - If this clause is matched, then the set statements
are executed and then we goto the nth clause, or the
first clause greater than this. In order to ensure
route-maps *always* exit, you cannot jump backwards.
@@ -3161,11 +3202,21 @@ void route_map_rule_tag_free(void *rule)
void route_map_finish(void)
{
int i;
+ struct route_map_rule_cmd_proxy *proxy;
+
+ /* these 2 hash tables have INIT_HASH initializers, so the "default"
+ * state is "initialized & empty" => fini() followed by init() to
+ * return to that same state
+ */
+ while ((proxy = rmap_cmd_name_pop(rmap_match_cmds)))
+ (void)proxy;
+ rmap_cmd_name_fini(rmap_match_cmds);
+ rmap_cmd_name_init(rmap_match_cmds);
- vector_free(route_match_vec);
- route_match_vec = NULL;
- vector_free(route_set_vec);
- route_set_vec = NULL;
+ while ((proxy = rmap_cmd_name_pop(rmap_set_cmds)))
+ (void)proxy;
+ rmap_cmd_name_fini(rmap_set_cmds);
+ rmap_cmd_name_init(rmap_set_cmds);
/*
* All protocols are setting these to NULL
@@ -3309,9 +3360,6 @@ void route_map_init(void)
{
int i;
- /* Make vector for match and set. */
- route_match_vec = vector_init(1);
- route_set_vec = vector_init(1);
route_map_master_hash =
hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp,
"Route Map Master Hash");
diff --git a/lib/routemap.h b/lib/routemap.h
index 2c8eb24537..6c4916898a 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -21,6 +21,7 @@
#ifndef _ZEBRA_ROUTEMAP_H
#define _ZEBRA_ROUTEMAP_H
+#include "typesafe.h"
#include "prefix.h"
#include "memory.h"
#include "qobj.h"
@@ -243,12 +244,16 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(C, "frr-route-map:ipv6-address-list"))
#define IS_MATCH_IPv4_NEXTHOP_LIST(C) \
(strmatch(C, "frr-route-map:ipv4-next-hop-list"))
+#define IS_MATCH_IPv6_NEXTHOP_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv6-next-hop-list"))
#define IS_MATCH_IPv4_PREFIX_LIST(C) \
(strmatch(C, "frr-route-map:ipv4-prefix-list"))
#define IS_MATCH_IPv6_PREFIX_LIST(C) \
(strmatch(C, "frr-route-map:ipv6-prefix-list"))
#define IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(C) \
(strmatch(C, "frr-route-map:ipv4-next-hop-prefix-list"))
+#define IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(C) \
+ (strmatch(C, "frr-route-map:ipv6-next-hop-prefix-list"))
#define IS_MATCH_IPv4_NEXTHOP_TYPE(C) \
(strmatch(C, "frr-route-map:ipv4-next-hop-type"))
#define IS_MATCH_IPv6_NEXTHOP_TYPE(C) \
@@ -422,8 +427,37 @@ extern enum rmap_compile_rets
route_map_delete_set(struct route_map_index *index,
const char *set_name, const char *set_arg);
+/* struct route_map_rule_cmd is kept const in order to not have writable
+ * function pointers (which is a security benefit.) Hence, below struct is
+ * used as proxy for hashing these for by-name lookup.
+ */
+
+PREDECL_HASH(rmap_cmd_name);
+
+struct route_map_rule_cmd_proxy {
+ struct rmap_cmd_name_item itm;
+ const struct route_map_rule_cmd *cmd;
+};
+
+/* ... and just automatically create a proxy struct for each call location
+ * to route_map_install_{match,set} to avoid unnecessarily added boilerplate
+ * for each route-map user
+ */
+
+#define route_map_install_match(c) \
+ do { \
+ static struct route_map_rule_cmd_proxy proxy = {.cmd = c}; \
+ _route_map_install_match(&proxy); \
+ } while (0)
+
+#define route_map_install_set(c) \
+ do { \
+ static struct route_map_rule_cmd_proxy proxy = {.cmd = c}; \
+ _route_map_install_set(&proxy); \
+ } while (0)
+
/* Install rule command to the match list. */
-extern void route_map_install_match(const struct route_map_rule_cmd *cmd);
+extern void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy);
/*
* Install rule command to the set list.
@@ -434,7 +468,7 @@ extern void route_map_install_match(const struct route_map_rule_cmd *cmd);
* in the apply command). See 'set metric' command
* as it is handled in ripd/ripngd and ospfd.
*/
-extern void route_map_install_set(const struct route_map_rule_cmd *cmd);
+extern void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy);
/* Lookup route map by name. */
extern struct route_map *route_map_lookup_by_name(const char *name);
@@ -525,9 +559,16 @@ extern void route_map_match_ip_next_hop_hook(int (*func)(
char *errmsg, size_t errmsg_len));
/* no match ip next hop */
extern void route_map_no_match_ip_next_hop_hook(int (*func)(
- struct route_map_index *index, const char *command,
- const char *arg, route_map_event_t type,
- char *errmsg, size_t errmsg_len));
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len));
+/* match ipv6 next hop */
+extern void route_map_match_ipv6_next_hop_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len));
+/* no match ipv6 next hop */
+extern void route_map_no_match_ipv6_next_hop_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len));
/* match ip next hop prefix list */
extern void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
struct route_map_index *index, const char *command,
@@ -578,6 +619,14 @@ extern void route_map_no_match_ipv6_next_hop_type_hook(int (*func)(
struct route_map_index *index, const char *command,
const char *arg, route_map_event_t type,
char *errmsg, size_t errmsg_len));
+/* match ipv6 next-hop prefix-list */
+extern void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len));
+/* no match ipv6 next-hop prefix-list */
+extern void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)(
+ struct route_map_index *index, const char *command, const char *arg,
+ route_map_event_t type, char *errmsg, size_t errmsg_len));
/* match metric */
extern void route_map_match_metric_hook(int (*func)(
struct route_map_index *index, const char *command,
@@ -713,6 +762,33 @@ struct route_map_match_set_hooks {
route_map_event_t type,
char *errmsg, size_t errmsg_len);
+ /* match ipv6 next hop */
+ int (*match_ipv6_next_hop)(struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type, char *errmsg,
+ size_t errmsg_len);
+
+ /* no match ipv6 next hop */
+ int (*no_match_ipv6_next_hop)(struct route_map_index *index,
+ const char *command, const char *arg,
+ route_map_event_t type, char *errmsg,
+ size_t errmsg_len);
+
+ /* match ipv6 next hop prefix-list */
+ int (*match_ipv6_next_hop_prefix_list)(struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type,
+ char *errmsg, size_t errmsg_len);
+
+ /* no match ipv6 next-hop prefix-list */
+ int (*no_match_ipv6_next_hop_prefix_list)(struct route_map_index *index,
+ const char *command,
+ const char *arg,
+ route_map_event_t type,
+ char *errmsg,
+ size_t errmsg_len);
+
/* match ip next hop prefix list */
int (*match_ip_next_hop_prefix_list)(struct route_map_index *index,
const char *command,
@@ -908,25 +984,28 @@ void routemap_hook_context_free(struct routemap_hook_context *rhc);
extern const struct frr_yang_module_info frr_route_map_info;
/* routemap_cli.c */
-extern int route_map_instance_cmp(struct lyd_node *dnode1,
- struct lyd_node *dnode2);
-extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+extern int route_map_instance_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
+extern void route_map_instance_show(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
extern void route_map_instance_show_end(struct vty *vty,
- struct lyd_node *dnode);
-extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+ const struct lyd_node *dnode);
+extern void route_map_condition_show(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
-extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+extern void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
-extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+extern void route_map_exit_policy_show(struct vty *vty,
+ const struct lyd_node *dnode,
bool show_defaults);
-extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+extern void route_map_call_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
extern void route_map_description_show(struct vty *vty,
- struct lyd_node *dnode,
+ const struct lyd_node *dnode,
bool show_defaults);
extern void route_map_optimization_disabled_show(struct vty *vty,
- struct lyd_node *dnode,
+ const struct lyd_node *dnode,
bool show_defaults);
extern void route_map_cli_init(void);
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index cadad15fa7..2685bd2d79 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -41,7 +41,7 @@
DEFPY_YANG_NOSH(
route_map, route_map_cmd,
- "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ "route-map RMAP_NAME$name <deny|permit>$action (1-65535)$sequence",
ROUTE_MAP_CMD_STR
ROUTE_MAP_OP_CMD_STR
ROUTE_MAP_SEQUENCE_CMD_STR)
@@ -71,7 +71,7 @@ DEFPY_YANG_NOSH(
DEFPY_YANG(
no_route_map_all, no_route_map_all_cmd,
- "no route-map WORD$name",
+ "no route-map RMAP_NAME$name",
NO_STR
ROUTE_MAP_CMD_STR)
{
@@ -86,7 +86,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_route_map, no_route_map_cmd,
- "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ "no route-map RMAP_NAME$name <deny|permit>$action (1-65535)$sequence",
NO_STR
ROUTE_MAP_CMD_STR
ROUTE_MAP_OP_CMD_STR
@@ -103,7 +103,8 @@ DEFPY_YANG(
return nb_cli_apply_changes(vty, NULL);
}
-int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+int route_map_instance_cmp(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2)
{
uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence");
uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence");
@@ -111,7 +112,7 @@ int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
return seq1 - seq2;
}
-void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_instance_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
const char *name = yang_dnode_get_string(dnode, "../name");
@@ -122,7 +123,7 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
}
-void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
+void route_map_instance_show_end(struct vty *vty, const struct lyd_node *dnode)
{
vty_out(vty, "exit\n");
vty_out(vty, "!\n");
@@ -165,12 +166,10 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_address, match_ip_address_cmd,
- "match ip address <(1-199)|(1300-2699)|WORD>$name",
+ "match ip address ACCESSLIST4_NAME$name",
MATCH_STR
IP_STR
"Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
const char *xpath =
@@ -187,13 +186,11 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ip_address, no_match_ip_address_cmd,
- "no match ip address [<(1-199)|(1300-2699)|WORD>]",
+ "no match ip address [ACCESSLIST4_NAME]",
NO_STR
MATCH_STR
IP_STR
"Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
const char *xpath =
@@ -207,7 +204,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_address_prefix_list,
match_ip_address_prefix_list_cmd,
- "match ip address prefix-list WORD$name",
+ "match ip address prefix-list PREFIXLIST_NAME$name",
MATCH_STR
IP_STR
"Match address of route\n"
@@ -228,7 +225,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
- "no match ip address prefix-list [WORD]",
+ "no match ip address prefix-list [PREFIXLIST_NAME]",
NO_STR
MATCH_STR
IP_STR
@@ -246,12 +243,10 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_next_hop, match_ip_next_hop_cmd,
- "match ip next-hop <(1-199)|(1300-2699)|WORD>$name",
+ "match ip next-hop ACCESSLIST4_NAME$name",
MATCH_STR
IP_STR
"Match next-hop address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
const char *xpath =
@@ -268,13 +263,11 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ip_next_hop, no_match_ip_next_hop_cmd,
- "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
+ "no match ip next-hop [ACCESSLIST4_NAME]",
NO_STR
MATCH_STR
IP_STR
"Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
"IP Access-list name\n")
{
const char *xpath =
@@ -288,7 +281,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_next_hop_prefix_list,
match_ip_next_hop_prefix_list_cmd,
- "match ip next-hop prefix-list WORD$name",
+ "match ip next-hop prefix-list PREFIXLIST_NAME$name",
MATCH_STR
IP_STR
"Match next-hop address of route\n"
@@ -310,7 +303,7 @@ DEFPY_YANG(
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]",
+ "no match ip next-hop prefix-list [PREFIXLIST_NAME]",
NO_STR
MATCH_STR
IP_STR
@@ -365,7 +358,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ipv6_address, match_ipv6_address_cmd,
- "match ipv6 address WORD$name",
+ "match ipv6 address ACCESSLIST6_NAME$name",
MATCH_STR
IPV6_STR
"Match IPv6 address of route\n"
@@ -385,7 +378,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ipv6_address, no_match_ipv6_address_cmd,
- "no match ipv6 address [WORD]",
+ "no match ipv6 address [ACCESSLIST6_NAME]",
NO_STR
MATCH_STR
IPV6_STR
@@ -402,7 +395,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
- "match ipv6 address prefix-list WORD$name",
+ "match ipv6 address prefix-list PREFIXLIST_NAME$name",
MATCH_STR
IPV6_STR
"Match address of route\n"
@@ -424,7 +417,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ipv6_address_prefix_list,
no_match_ipv6_address_prefix_list_cmd,
- "no match ipv6 address prefix-list [WORD]",
+ "no match ipv6 address prefix-list [PREFIXLIST_NAME]",
NO_STR
MATCH_STR
IPV6_STR
@@ -546,31 +539,29 @@ DEFPY_YANG(
return nb_cli_apply_changes(vty, NULL);
}
-void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
const char *condition = yang_dnode_get_string(dnode, "./condition");
- struct lyd_node *ln;
+ const struct lyd_node *ln;
const char *acl;
if (IS_MATCH_INTERFACE(condition)) {
vty_out(vty, " match interface %s\n",
yang_dnode_get_string(
dnode, "./rmap-match-condition/interface"));
- } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition)
- || IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(dnode,
- "./rmap-match-condition/list-name"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
-
- assert(acl);
-
- if (IS_MATCH_IPv4_ADDRESS_LIST(condition))
- vty_out(vty, " match ip address %s\n", acl);
- else
- vty_out(vty, " match ip next-hop %s\n", acl);
+ } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) {
+ vty_out(vty, " match ip address %s\n",
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
+ vty_out(vty, " match ip next-hop %s\n",
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) {
+ vty_out(vty, " match ipv6 next-hop %s\n",
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
} else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
vty_out(vty, " match ip address prefix-list %s\n",
yang_dnode_get_string(
@@ -579,6 +570,10 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " match ip next-hop prefix-list %s\n",
yang_dnode_get_string(
dnode, "./rmap-match-condition/list-name"));
+ } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) {
+ vty_out(vty, " match ipv6 next-hop prefix-list %s\n",
+ yang_dnode_get_string(
+ dnode, "./rmap-match-condition/list-name"));
} else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
vty_out(vty, " match ipv6 address %s\n",
yang_dnode_get_string(
@@ -719,91 +714,47 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
dnode,
"./rmap-match-condition/frr-bgp-route-map:list-name"));
} else if (IS_MATCH_ROUTE_SRC(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:list-name"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
-
- assert(acl);
-
- vty_out(vty, " match ip route-source %s\n", acl);
+ vty_out(vty, " match ip route-source %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:list-name"));
} else if (IS_MATCH_ROUTE_SRC_PL(condition)) {
vty_out(vty, " match ip route-source prefix-list %s\n",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:list-name"));
- } else if (IS_MATCH_ROUTE_SRC(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:list-name"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
-
- assert(acl);
-
- vty_out(vty, " match ip route-source %s\n", acl);
} else if (IS_MATCH_COMMUNITY(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
- != NULL) {
- acl = yang_dnode_get_string(ln, NULL);
-
- if (true
- == yang_dnode_get_bool(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
- vty_out(vty,
- " match community %s exact-match\n",
- acl);
- else
- vty_out(vty, " match community %s\n", acl);
- }
-
- assert(acl);
+ vty_out(vty, " match community %s",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"));
+ if (yang_dnode_get_bool(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
+ vty_out(vty, " exact-match");
+ vty_out(vty, "\n");
} else if (IS_MATCH_LCOMMUNITY(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
- != NULL) {
- acl = yang_dnode_get_string(ln, NULL);
-
- if (true
- == yang_dnode_get_bool(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
- vty_out(vty,
- " match large-community %s exact-match\n",
- acl);
- else
- vty_out(vty, " match large-community %s\n",
- acl);
- }
-
- assert(acl);
+ vty_out(vty, " match large-community %s",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"));
+ if (yang_dnode_get_bool(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
+ vty_out(vty, " exact-match");
+ vty_out(vty, "\n");
} else if (IS_MATCH_EXTCOMMUNITY(condition)) {
- acl = NULL;
- if ((ln = yang_dnode_get(
- dnode,
- "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"))
- != NULL)
- acl = yang_dnode_get_string(ln, NULL);
-
- assert(acl);
-
- vty_out(vty, " match extcommunity %s\n", acl);
+ vty_out(vty, " match extcommunity %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"));
} else if (IS_MATCH_IPV4_NH(condition)) {
- vty_out(vty, " match ip next-hop %s\n",
+ vty_out(vty, " match ip next-hop address %s\n",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:ipv4-address"));
} else if (IS_MATCH_IPV6_NH(condition)) {
- vty_out(vty, " match ipv6 next-hop %s\n",
+ vty_out(vty, " match ipv6 next-hop address %s\n",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:ipv6-address"));
@@ -1021,11 +972,11 @@ DEFUN_YANG (no_set_srte_color,
}
-void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
const char *action = yang_dnode_get_string(dnode, "./action");
- struct lyd_node *ln;
+ const struct lyd_node *ln;
const char *acl;
if (IS_SET_IPv4_NH(action)) {
@@ -1363,7 +1314,7 @@ ALIAS_YANG(
"Continue on a different entry within the route-map\n"
"Route-map entry sequence number\n")
-void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_exit_policy_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
int exit_policy = yang_dnode_get_enum(dnode, NULL);
@@ -1405,7 +1356,7 @@ DEFPY_YANG(
return nb_cli_apply_changes(vty, NULL);
}
-void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_call_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
@@ -1439,7 +1390,7 @@ DEFUN_YANG (no_rmap_description,
return nb_cli_apply_changes(vty, NULL);
}
-void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
+void route_map_description_show(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
@@ -1447,7 +1398,7 @@ void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
DEFPY_YANG(
route_map_optimization, route_map_optimization_cmd,
- "[no] route-map WORD$name optimization",
+ "[no] route-map RMAP_NAME$name optimization",
NO_STR
ROUTE_MAP_CMD_STR
"Configure route-map optimization\n")
@@ -1468,7 +1419,7 @@ DEFPY_YANG(
}
void route_map_optimization_disabled_show(struct vty *vty,
- struct lyd_node *dnode,
+ const struct lyd_node *dnode,
bool show_defaults)
{
const char *name = yang_dnode_get_string(dnode, "../name");
@@ -1515,7 +1466,7 @@ DEFPY_HIDDEN(
static int route_map_config_write(struct vty *vty)
{
- struct lyd_node *dnode;
+ const struct lyd_node *dnode;
int written = 0;
dnode = yang_dnode_get(running_config->dnode,
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index 3473ca2aea..51b879959f 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -601,6 +601,16 @@ static int lib_route_map_entry_match_condition_list_name_modify(
rhc->rhc_rmi, "ip next-hop", acl,
RMAP_EVENT_FILTER_ADDED,
args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) {
+ if (rmap_match_set_hook.match_ipv6_next_hop == NULL)
+ return NB_OK;
+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop;
+ rhc->rhc_rule = "ipv6 next-hop";
+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+ rv = rmap_match_set_hook.match_ipv6_next_hop(
+ rhc->rhc_rmi, "ipv6 next-hop", acl,
+ RMAP_EVENT_FILTER_ADDED, args->errmsg,
+ args->errmsg_len);
} else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
return NB_OK;
@@ -612,6 +622,16 @@ static int lib_route_map_entry_match_condition_list_name_modify(
rhc->rhc_rmi, "ip next-hop prefix-list", acl,
RMAP_EVENT_PLIST_ADDED,
args->errmsg, args->errmsg_len);
+ } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) {
+ if (rmap_match_set_hook.match_ipv6_next_hop_prefix_list == NULL)
+ return NB_OK;
+ rhc->rhc_mhook =
+ rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list;
+ rhc->rhc_rule = "ipv6 next-hop prefix-list";
+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+ rv = rmap_match_set_hook.match_ipv6_next_hop_prefix_list(
+ rhc->rhc_rmi, "ipv6 next-hop prefix-list", acl,
+ RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len);
} else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
if (rmap_match_set_hook.match_ipv6_address == NULL)
return NB_OK;
diff --git a/lib/sbuf.h b/lib/sbuf.h
index 9f0311006d..aaa2db0edb 100644
--- a/lib/sbuf.h
+++ b/lib/sbuf.h
@@ -35,7 +35,7 @@ extern "C" {
* without any information about the previous parsing steps, is usually not very
* helpful.
* Using sbuf, the parser can log the whole parsing process into a buffer using
- * a printf like API. When an error ocurrs, all the information about previous
+ * a printf like API. When an error occurs, all the information about previous
* parsing steps is there in the log, without any need for backtracking, and can
* be used to give a detailed and useful error description.
* When parsing completes successfully without any error, the log can just be
diff --git a/lib/sigevent.c b/lib/sigevent.c
index be7297f264..00bc31f517 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -36,10 +36,10 @@
/* master signals descriptor struct */
-static struct quagga_sigevent_master_t {
+static struct frr_sigevent_master_t {
struct thread *t;
- struct quagga_signal_t *signals;
+ struct frr_signal_t *signals;
int sigc;
volatile sig_atomic_t caught;
@@ -48,10 +48,10 @@ static struct quagga_sigevent_master_t {
/* Generic signal handler
* Schedules signal event thread
*/
-static void quagga_signal_handler(int signo)
+static void frr_signal_handler(int signo)
{
int i;
- struct quagga_signal_t *sig;
+ struct frr_signal_t *sig;
for (i = 0; i < sigmaster.sigc; i++) {
sig = &(sigmaster.signals[i]);
@@ -91,12 +91,12 @@ bool frr_sigevent_check(sigset_t *setp)
}
/* check if signals have been caught and run appropriate handlers */
-int quagga_sigevent_process(void)
+int frr_sigevent_process(void)
{
- struct quagga_signal_t *sig;
+ struct frr_signal_t *sig;
int i;
#ifdef SIGEVENT_BLOCK_SIGNALS
- /* shouldnt need to block signals, but potentially may be needed */
+ /* shouldn't need to block signals, but potentially may be needed */
sigset_t newmask, oldmask;
/*
@@ -110,7 +110,7 @@ int quagga_sigevent_process(void)
if ((sigprocmask(SIG_BLOCK, &newmask, &oldmask)) < 0) {
flog_err_sys(EC_LIB_SYSTEM_CALL,
- "quagga_signal_timer: couldnt block signals!");
+ "frr_signal_timer: couldnt block signals!");
return -1;
}
#endif /* SIGEVENT_BLOCK_SIGNALS */
@@ -142,16 +142,16 @@ int quagga_sigevent_process(void)
}
#ifdef SIGEVENT_SCHEDULE_THREAD
-/* timer thread to check signals. Shouldnt be needed */
-int quagga_signal_timer(struct thread *t)
+/* timer thread to check signals. shouldn't be needed */
+int frr_signal_timer(struct thread *t)
{
- struct quagga_sigevent_master_t *sigm;
+ struct frr_sigevent_master_t *sigm;
sigm = THREAD_ARG(t);
sigm->t = NULL;
- thread_add_timer(sigm->t->master, quagga_signal_timer, &sigmaster,
- QUAGGA_SIGNAL_TIMER_INTERVAL, &sigm->t);
- return quagga_sigevent_process();
+ thread_add_timer(sigm->t->master, frr_signal_timer, &sigmaster,
+ FRR_SIGNAL_TIMER_INTERVAL, &sigm->t);
+ return frr_sigevent_process();
}
#endif /* SIGEVENT_SCHEDULE_THREAD */
@@ -163,7 +163,7 @@ static int signal_set(int signo)
struct sigaction sig;
struct sigaction osig;
- sig.sa_handler = &quagga_signal_handler;
+ sig.sa_handler = &frr_signal_handler;
sigfillset(&sig.sa_mask);
sig.sa_flags = 0;
if (signo == SIGALRM) {
@@ -348,11 +348,11 @@ static void trap_default_signals(void)
}
void signal_init(struct thread_master *m, int sigc,
- struct quagga_signal_t signals[])
+ struct frr_signal_t signals[])
{
int i = 0;
- struct quagga_signal_t *sig;
+ struct frr_signal_t *sig;
/* First establish some default handlers that can be overridden by
the application. */
@@ -370,7 +370,7 @@ void signal_init(struct thread_master *m, int sigc,
#ifdef SIGEVENT_SCHEDULE_THREAD
sigmaster.t = NULL;
- thread_add_timer(m, quagga_signal_timer, &sigmaster,
- QUAGGA_SIGNAL_TIMER_INTERVAL, &sigmaster.t);
+ thread_add_timer(m, frr_signal_timer, &sigmaster,
+ FRR_SIGNAL_TIMER_INTERVAL, &sigmaster.t);
#endif /* SIGEVENT_SCHEDULE_THREAD */
}
diff --git a/lib/sigevent.h b/lib/sigevent.h
index 4a39b22889..dd1ee99587 100644
--- a/lib/sigevent.h
+++ b/lib/sigevent.h
@@ -20,8 +20,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _QUAGGA_SIGNAL_H
-#define _QUAGGA_SIGNAL_H
+#ifndef _FRR_SIGNAL_H
+#define _FRR_SIGNAL_H
#include <thread.h>
@@ -29,9 +29,9 @@
extern "C" {
#endif
-#define QUAGGA_SIGNAL_TIMER_INTERVAL 2L
+#define FRR_SIGNAL_TIMER_INTERVAL 2L
-struct quagga_signal_t {
+struct frr_signal_t {
int signal; /* signal number */
void (*handler)(void); /* handler to call */
@@ -42,11 +42,11 @@ struct quagga_signal_t {
* takes:
* - pointer to valid struct thread_master
* - number of elements in passed in signals array
- * - array of quagga_signal_t's describing signals to handle
+ * - array of frr_signal_t's describing signals to handle
* and handlers to use for each signal
*/
extern void signal_init(struct thread_master *m, int sigc,
- struct quagga_signal_t *signals);
+ struct frr_signal_t *signals);
/*
@@ -58,10 +58,10 @@ extern void signal_init(struct thread_master *m, int sigc,
bool frr_sigevent_check(sigset_t *setp);
/* check whether there are signals to handle, process any found */
-extern int quagga_sigevent_process(void);
+extern int frr_sigevent_process(void);
#ifdef __cplusplus
}
#endif
-#endif /* _QUAGGA_SIGNAL_H */
+#endif /* _FRR_SIGNAL_H */
diff --git a/lib/skiplist.c b/lib/skiplist.c
index c5219f7381..81407826f2 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -21,7 +21,7 @@
*/
/*
- * Skip List impementation based on code from William Pugh.
+ * Skip List implementation based on code from William Pugh.
* ftp://ftp.cs.umd.edu/pub/skipLists/
*
* Skip Lists are a probabilistic alternative to balanced trees, as
diff --git a/lib/skiplist.h b/lib/skiplist.h
index 00950e13bb..165607820a 100644
--- a/lib/skiplist.h
+++ b/lib/skiplist.h
@@ -21,7 +21,7 @@
*/
/*
- * Skip List impementation based on code from William Pugh.
+ * Skip List implementation based on code from William Pugh.
* ftp://ftp.cs.umd.edu/pub/skipLists/
*/
diff --git a/lib/snmp.c b/lib/snmp.c
index 23d3f38b31..8d8b3c950c 100644
--- a/lib/snmp.c
+++ b/lib/snmp.c
@@ -25,13 +25,11 @@
#include "smux.h"
-#define min(A,B) ((A) < (B) ? (A) : (B))
-
int oid_compare(const oid *o1, int o1_len, const oid *o2, int o2_len)
{
int i;
- for (i = 0; i < min(o1_len, o2_len); i++) {
+ for (i = 0; i < MIN(o1_len, o2_len); i++) {
if (o1[i] < o2[i])
return -1;
else if (o1[i] > o2[i])
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 150736e00c..45f3c23330 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -122,7 +122,7 @@ int setsockopt_ipv6_pktinfo(int sock, int val)
if (ret < 0)
flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_PKTINFO : %s",
safe_strerror(errno));
-#endif /* INIA_IPV6 */
+#endif /* IANA_IPV6 */
return ret;
}
@@ -595,7 +595,7 @@ int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen,
/* If this does not work, then all users of this sockopt will
* need to
- * differentiate between IPv4 and IPv6, and keep seperate
+ * differentiate between IPv4 and IPv6, and keep separate
* sockets for
* each.
*
diff --git a/lib/srv6.c b/lib/srv6.c
index ccb94b2f76..6a658444c6 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -161,21 +161,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk)
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk)
{
- char str[256];
json_object *jo_root = NULL;
jo_root = json_object_new_object();
- prefix2str(&chunk->prefix, str, sizeof(str));
- json_object_string_add(jo_root, "prefix", str);
+ json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix);
json_object_string_add(jo_root, "proto",
zebra_route_string(chunk->proto));
return jo_root;
}
+json_object *
+srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk)
+{
+ json_object *jo_root = NULL;
+
+ jo_root = json_object_new_object();
+
+ /* set prefix */
+ json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix);
+
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength",
+ chunk->block_bits_length);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength", chunk->node_bits_length);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ chunk->function_bits_length);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ chunk->argument_bits_length);
+
+ /* set keep */
+ json_object_int_add(jo_root, "keep", chunk->keep);
+
+ /* set proto */
+ json_object_string_add(jo_root, "proto",
+ zebra_route_string(chunk->proto));
+
+ /* set instance */
+ json_object_int_add(jo_root, "instance", chunk->instance);
+
+ /* set session_id */
+ json_object_int_add(jo_root, "sessionId", chunk->session_id);
+
+ return jo_root;
+}
+
json_object *srv6_locator_json(const struct srv6_locator *loc)
{
- char str[256];
struct listnode *node;
struct srv6_locator_chunk *chunk;
json_object *jo_root = NULL;
@@ -188,8 +226,7 @@ json_object *srv6_locator_json(const struct srv6_locator *loc)
json_object_string_add(jo_root, "name", loc->name);
/* set prefix */
- prefix2str(&loc->prefix, str, sizeof(str));
- json_object_string_add(jo_root, "prefix", str);
+ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix);
/* set function_bits_length */
json_object_int_add(jo_root, "functionBitsLength",
@@ -209,3 +246,50 @@ json_object *srv6_locator_json(const struct srv6_locator *loc)
return jo_root;
}
+
+json_object *srv6_locator_detailed_json(const struct srv6_locator *loc)
+{
+ struct listnode *node;
+ struct srv6_locator_chunk *chunk;
+ json_object *jo_root = NULL;
+ json_object *jo_chunk = NULL;
+ json_object *jo_chunks = NULL;
+
+ jo_root = json_object_new_object();
+
+ /* set name */
+ json_object_string_add(jo_root, "name", loc->name);
+
+ /* set prefix */
+ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix);
+
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ loc->function_bits_length);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->argument_bits_length);
+
+ /* set algonum */
+ json_object_int_add(jo_root, "algoNum", loc->algonum);
+
+ /* set status_up */
+ json_object_boolean_add(jo_root, "statusUp", loc->status_up);
+
+ /* set chunks */
+ jo_chunks = json_object_new_array();
+ json_object_object_add(jo_root, "chunks", jo_chunks);
+ for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
+ jo_chunk = srv6_locator_chunk_detailed_json(chunk);
+ json_object_array_add(jo_chunks, jo_chunk);
+ }
+
+ return jo_root;
+}
diff --git a/lib/srv6.h b/lib/srv6.h
index 715fc3723b..e0db30cd13 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -189,6 +189,9 @@ extern void srv6_locator_free(struct srv6_locator *locator);
extern void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk);
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk);
json_object *srv6_locator_json(const struct srv6_locator *loc);
+json_object *srv6_locator_detailed_json(const struct srv6_locator *loc);
+json_object *
+srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk);
#ifdef __cplusplus
}
diff --git a/lib/subdir.am b/lib/subdir.am
index dab5fb9e83..bb10d71ed1 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -3,7 +3,7 @@
#
lib_LTLIBRARIES += lib/libfrr.la
lib_libfrr_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 -Xlinker -e_libfrr_version
-lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBM)
+lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBCRYPT) $(LIBDL) $(LIBM)
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
@@ -130,7 +130,6 @@ nodist_lib_libfrr_la_SOURCES = \
yang/ietf/ietf-interfaces.yang.c \
yang/ietf/ietf-bgp-types.yang.c \
yang/frr-module-translator.yang.c \
- yang/frr-nexthop.yang.c \
# end
vtysh_scan += \
diff --git a/lib/table.c b/lib/table.c
index e6030ca4ca..523183bef2 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -393,7 +393,7 @@ void route_node_delete(struct route_node *node)
route_node_delete(parent);
}
-/* Get fist node and lock it. This function is useful when one want
+/* Get first node and lock it. This function is useful when one wants
to lookup all the node exist in the routing table. */
struct route_node *route_top(struct route_table *table)
{
diff --git a/lib/thread.c b/lib/thread.c
index 835aa38115..7b223ed6de 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -922,10 +922,10 @@ done:
}
/* Add new read thread. */
-struct thread *_thread_add_read_write(const struct xref_threadsched *xref,
- struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, int fd, struct thread **t_ptr)
+void _thread_add_read_write(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *), void *arg, int fd,
+ struct thread **t_ptr)
{
int dir = xref->thread_type;
struct thread *thread = NULL;
@@ -1000,15 +1000,13 @@ struct thread *_thread_add_read_write(const struct xref_threadsched *xref,
AWAKEN(m);
}
-
- return thread;
}
-static struct thread *
-_thread_add_timer_timeval(const struct xref_threadsched *xref,
- struct thread_master *m, int (*func)(struct thread *),
- void *arg, struct timeval *time_relative,
- struct thread **t_ptr)
+static void _thread_add_timer_timeval(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *), void *arg,
+ struct timeval *time_relative,
+ struct thread **t_ptr)
{
struct thread *thread;
struct timeval t;
@@ -1028,7 +1026,7 @@ _thread_add_timer_timeval(const struct xref_threadsched *xref,
frr_with_mutex(&m->mtx) {
if (t_ptr && *t_ptr)
/* thread is already scheduled; don't reschedule */
- return NULL;
+ return;
thread = thread_get(m, THREAD_TIMER, func, arg, xref);
@@ -1048,16 +1046,13 @@ _thread_add_timer_timeval(const struct xref_threadsched *xref,
if (thread_timer_list_first(&m->timer) == thread)
AWAKEN(m);
}
-
- return thread;
}
/* Add timer event thread. */
-struct thread *_thread_add_timer(const struct xref_threadsched *xref,
- struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, long timer, struct thread **t_ptr)
+void _thread_add_timer(const struct xref_threadsched *xref,
+ struct thread_master *m, int (*func)(struct thread *),
+ void *arg, long timer, struct thread **t_ptr)
{
struct timeval trel;
@@ -1066,15 +1061,14 @@ struct thread *_thread_add_timer(const struct xref_threadsched *xref,
trel.tv_sec = timer;
trel.tv_usec = 0;
- return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
+ _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
}
/* Add timer event thread with "millisecond" resolution */
-struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref,
- struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, long timer,
- struct thread **t_ptr)
+void _thread_add_timer_msec(const struct xref_threadsched *xref,
+ struct thread_master *m,
+ int (*func)(struct thread *), void *arg, long timer,
+ struct thread **t_ptr)
{
struct timeval trel;
@@ -1083,24 +1077,21 @@ struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref,
trel.tv_sec = timer / 1000;
trel.tv_usec = 1000 * (timer % 1000);
- return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
+ _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr);
}
/* Add timer event thread with "timeval" resolution */
-struct thread *_thread_add_timer_tv(const struct xref_threadsched *xref,
- struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, struct timeval *tv,
- struct thread **t_ptr)
+void _thread_add_timer_tv(const struct xref_threadsched *xref,
+ struct thread_master *m, int (*func)(struct thread *),
+ void *arg, struct timeval *tv, struct thread **t_ptr)
{
- return _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
+ _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr);
}
/* Add simple event thread. */
-struct thread *_thread_add_event(const struct xref_threadsched *xref,
- struct thread_master *m,
- int (*func)(struct thread *),
- void *arg, int val, struct thread **t_ptr)
+void _thread_add_event(const struct xref_threadsched *xref,
+ struct thread_master *m, int (*func)(struct thread *),
+ void *arg, int val, struct thread **t_ptr)
{
struct thread *thread = NULL;
@@ -1128,8 +1119,6 @@ struct thread *_thread_add_event(const struct xref_threadsched *xref,
AWAKEN(m);
}
-
- return thread;
}
/* Thread cancellation ------------------------------------------------------ */
@@ -1706,7 +1695,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
do {
/* Handle signals if any */
if (m->handle_signals)
- quagga_sigevent_process();
+ frr_sigevent_process();
pthread_mutex_lock(&m->mtx);
@@ -2059,3 +2048,11 @@ void debug_signals(const sigset_t *sigs)
zlog_debug("%s: %s", __func__, buf);
}
+
+bool thread_is_scheduled(struct thread *thread)
+{
+ if (thread == NULL)
+ return false;
+
+ return true;
+}
diff --git a/lib/thread.h b/lib/thread.h
index abd94ff4f0..39f21da11d 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -219,26 +219,30 @@ void thread_master_set_name(struct thread_master *master, const char *name);
extern void thread_master_free(struct thread_master *);
extern void thread_master_free_unused(struct thread_master *);
-extern struct thread *_thread_add_read_write(
- const struct xref_threadsched *xref, struct thread_master *master,
- int (*fn)(struct thread *), void *arg, int fd, struct thread **tref);
-
-extern struct thread *_thread_add_timer(
- const struct xref_threadsched *xref, struct thread_master *master,
- int (*fn)(struct thread *), void *arg, long t, struct thread **tref);
-
-extern struct thread *_thread_add_timer_msec(
- const struct xref_threadsched *xref, struct thread_master *master,
- int (*fn)(struct thread *), void *arg, long t, struct thread **tref);
-
-extern struct thread *_thread_add_timer_tv(
- const struct xref_threadsched *xref, struct thread_master *master,
- int (*fn)(struct thread *), void *arg, struct timeval *tv,
- struct thread **tref);
-
-extern struct thread *_thread_add_event(
- const struct xref_threadsched *xref, struct thread_master *master,
- int (*fn)(struct thread *), void *arg, int val, struct thread **tref);
+extern void _thread_add_read_write(const struct xref_threadsched *xref,
+ struct thread_master *master,
+ int (*fn)(struct thread *), void *arg,
+ int fd, struct thread **tref);
+
+extern void _thread_add_timer(const struct xref_threadsched *xref,
+ struct thread_master *master,
+ int (*fn)(struct thread *), void *arg, long t,
+ struct thread **tref);
+
+extern void _thread_add_timer_msec(const struct xref_threadsched *xref,
+ struct thread_master *master,
+ int (*fn)(struct thread *), void *arg,
+ long t, struct thread **tref);
+
+extern void _thread_add_timer_tv(const struct xref_threadsched *xref,
+ struct thread_master *master,
+ int (*fn)(struct thread *), void *arg,
+ struct timeval *tv, struct thread **tref);
+
+extern void _thread_add_event(const struct xref_threadsched *xref,
+ struct thread_master *master,
+ int (*fn)(struct thread *), void *arg, int val,
+ struct thread **tref);
extern void _thread_execute(const struct xref_threadsched *xref,
struct thread_master *master,
@@ -273,6 +277,7 @@ extern pthread_key_t thread_current;
extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
struct thread *t_timer);
+extern bool thread_is_scheduled(struct thread *thread);
/* Debug signal mask */
void debug_signals(const sigset_t *sigs);
diff --git a/lib/typerb.c b/lib/typerb.c
index 092faa4cc9..e1346df191 100644
--- a/lib/typerb.c
+++ b/lib/typerb.c
@@ -45,6 +45,7 @@
#include "config.h"
#endif
+#include <string.h>
#include "typerb.h"
#define RB_BLACK 0
@@ -330,6 +331,7 @@ color:
rbe_remove_color(rbt, parent, child);
rbt->count--;
+ memset(old, 0, sizeof(*old));
return (old);
}
@@ -478,3 +480,11 @@ struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
return parent;
}
+
+bool typed_rb_member(const struct typed_rb_root *rbt,
+ const struct typed_rb_entry *rbe)
+{
+ while (rbe->rbt_parent)
+ rbe = rbe->rbt_parent;
+ return rbe == rbt->rbt_root;
+}
diff --git a/lib/typerb.h b/lib/typerb.h
index cbed8d4893..75a1de77b3 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -20,6 +20,7 @@
#ifndef _FRR_TYPERB_H
#define _FRR_TYPERB_H
+#include <string.h>
#include "typesafe.h"
#ifdef __cplusplus
@@ -62,6 +63,8 @@ const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt,
const struct typed_rb_entry *b));
struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
+bool typed_rb_member(const struct typed_rb_root *rbt,
+ const struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
@@ -142,6 +145,11 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->rr.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typed_rb_member(&h->rr, &item->field.re); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
#define PREDECL_RBTREE_UNIQ(prefix) \
diff --git a/lib/typesafe.c b/lib/typesafe.c
index 76705fad0d..3b65a2d02a 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
#include "typesafe.h"
#include "memory.h"
@@ -29,6 +30,46 @@ DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
+struct slist_item typesafe_slist_sentinel = { NULL };
+
+bool typesafe_list_member(const struct slist_head *head,
+ const struct slist_item *item)
+{
+ struct slist_item *fromhead = head->first;
+ struct slist_item **fromnext = (struct slist_item **)&item->next;
+
+ while (fromhead != _SLIST_LAST) {
+ if (fromhead == item || fromnext == head->last_next)
+ return true;
+
+ fromhead = fromhead->next;
+ if (!*fromnext || *fromnext == _SLIST_LAST)
+ break;
+ fromnext = &(*fromnext)->next;
+ }
+
+ return false;
+}
+
+bool typesafe_dlist_member(const struct dlist_head *head,
+ const struct dlist_item *item)
+{
+ const struct dlist_item *fromhead = head->hitem.next;
+ const struct dlist_item *fromitem = item->next;
+
+ if (!item->prev || !item->next)
+ return false;
+
+ while (fromhead != &head->hitem && fromitem != item) {
+ if (fromitem == &head->hitem || fromhead == item)
+ return true;
+ fromhead = fromhead->next;
+ fromitem = fromitem->next;
+ }
+
+ return false;
+}
+
#if 0
static void hash_consistency_check(struct thash_head *head)
{
diff --git a/lib/typesafe.h b/lib/typesafe.h
index ecac1a4381..b284397d98 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -20,7 +20,6 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
-#include <assert.h>
#include "compiler.h"
#ifdef __cplusplus
@@ -78,8 +77,34 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
} \
/* ... */
+/* *_member via find - when there is no better membership check than find() */
+#define TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
+macro_inline bool prefix ## _member(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return item == prefix ## _const_find(h, item); \
+} \
+/* ... */
+
+/* *_member via find_gteq - same for non-unique containers */
+#define TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
+macro_inline bool prefix ## _member(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ const type *iter; \
+ for (iter = prefix ## _const_find_gteq(h, item); iter; \
+ iter = prefix ## _const_next(h, iter)) { \
+ if (iter == item) \
+ return true; \
+ if (cmpfn(iter, item) > 0) \
+ break; \
+ } \
+ return false; \
+} \
+/* ... */
+
/* SWAP_ALL_SIMPLE = for containers where the items don't point back to the
- * head *AND* the head doesn'T points to itself (= everything except LIST,
+ * head *AND* the head doesn't point to itself (= everything except LIST,
* DLIST and SKIPLIST), just switch out the entire head
*/
#define TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
@@ -106,6 +131,10 @@ struct slist_head {
size_t count;
};
+/* this replaces NULL as the value for ->next on the last item. */
+extern struct slist_item typesafe_slist_sentinel;
+#define _SLIST_LAST &typesafe_slist_sentinel
+
static inline void typesafe_list_add(struct slist_head *head,
struct slist_item **pos, struct slist_item *item)
{
@@ -116,6 +145,9 @@ static inline void typesafe_list_add(struct slist_head *head,
head->count++;
}
+extern bool typesafe_list_member(const struct slist_head *head,
+ const struct slist_item *item);
+
/* use as:
*
* PREDECL_LIST(namelist);
@@ -136,6 +168,7 @@ MACRO_REQUIRE_SEMICOLON() /* end */
macro_inline void prefix ## _init(struct prefix##_head *h) \
{ \
memset(h, 0, sizeof(*h)); \
+ h->sh.first = _SLIST_LAST; \
h->sh.last_next = &h->sh.first; \
} \
macro_inline void prefix ## _fini(struct prefix##_head *h) \
@@ -161,25 +194,27 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct slist_item **iter = &h->sh.first; \
- while (*iter && *iter != &item->field.si) \
+ while (*iter != _SLIST_LAST && *iter != &item->field.si) \
iter = &(*iter)->next; \
- if (!*iter) \
+ if (*iter == _SLIST_LAST) \
return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
- if (!item->field.si.next) \
+ if (item->field.si.next == _SLIST_LAST) \
h->sh.last_next = iter; \
+ item->field.si.next = NULL; \
return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
struct slist_item *sitem = h->sh.first; \
- if (!sitem) \
+ if (sitem == _SLIST_LAST) \
return NULL; \
h->sh.count--; \
h->sh.first = sitem->next; \
- if (h->sh.first == NULL) \
+ if (h->sh.first == _SLIST_LAST) \
h->sh.last_next = &h->sh.first; \
+ sitem->next = NULL; \
return container_of(sitem, type, field.si); \
} \
macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
@@ -195,13 +230,17 @@ macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
} \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
- return container_of_null(h->sh.first, type, field.si); \
+ if (h->sh.first != _SLIST_LAST) \
+ return container_of(h->sh.first, type, field.si); \
+ return NULL; \
} \
macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
const type *item) \
{ \
const struct slist_item *sitem = &item->field.si; \
- return container_of_null(sitem->next, type, field.si); \
+ if (sitem->next != _SLIST_LAST) \
+ return container_of(sitem->next, type, field.si); \
+ return NULL; \
} \
TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
@@ -210,12 +249,23 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
if (!item) \
return NULL; \
sitem = &item->field.si; \
- return container_of_null(sitem->next, type, field.si); \
+ if (sitem->next != _SLIST_LAST) \
+ return container_of(sitem->next, type, field.si); \
+ return NULL; \
} \
macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
+macro_pure bool prefix ## _anywhere(const type *item) \
+{ \
+ return item->field.si.next != NULL; \
+} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typesafe_list_member(&h->sh, &item->field.si); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* don't use these structs directly */
@@ -267,6 +317,9 @@ static inline void typesafe_dlist_swap_all(struct dlist_head *a,
}
}
+extern bool typesafe_dlist_member(const struct dlist_head *head,
+ const struct dlist_item *item);
+
/* double-linked list, for fast item deletion
*/
#define PREDECL_DLIST(prefix) \
@@ -321,6 +374,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
ditem->prev->next = ditem->next; \
ditem->next->prev = ditem->prev; \
h->dh.count--; \
+ ditem->prev = ditem->next = NULL; \
return container_of(ditem, type, field.di); \
} \
macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
@@ -354,6 +408,16 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->dh.count; \
} \
+macro_pure bool prefix ## _anywhere(const type *item) \
+{ \
+ const struct dlist_item *ditem = &item->field.di; \
+ return ditem->next && ditem->prev; \
+} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return typesafe_dlist_member(&h->dh, &item->field.di); \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* note: heap currently caps out at 4G items */
@@ -463,6 +527,14 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ uint32_t idx = item->field.hi.index; \
+ if (idx >= h->hh.count) \
+ return false; \
+ return h->hh.array[idx] == &item->field.hi; \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
extern void typesafe_heap_resize(struct heap_head *head, bool grow);
@@ -565,6 +637,7 @@ macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
+ item->field.si.next = NULL; \
return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
@@ -618,6 +691,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
return container_of(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
+TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
MACRO_REQUIRE_SEMICOLON() /* end */
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
@@ -633,6 +707,7 @@ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \
return 0; \
} \
_DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \
+TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */
@@ -799,6 +874,19 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
+macro_pure bool prefix ## _member(const struct prefix##_head *h, \
+ const type *item) \
+{ \
+ uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \
+ const struct thash_item *hitem = h->hh.entries[hbits]; \
+ while (hitem && hitem->hashval < hval) \
+ hitem = hitem->next; \
+ for (hitem = h->hh.entries[hbits]; hitem && hitem->hashval <= hval; \
+ hitem = hitem->next) \
+ if (hitem == &item->field.hi) \
+ return true; \
+ return false; \
+} \
MACRO_REQUIRE_SEMICOLON() /* end */
/* skiplist, sorted.
@@ -937,6 +1025,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
return container_of_null(sitem, type, field.si); \
} \
TYPESAFE_FIND(prefix, type) \
+TYPESAFE_MEMBER_VIA_FIND(prefix, type) \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp); \
@@ -968,6 +1057,7 @@ macro_inline int prefix ## __cmp_uq(const struct sskip_item *a, \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp_uq); \
+TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \
MACRO_REQUIRE_SEMICOLON() /* end */
diff --git a/lib/vector.c b/lib/vector.c
index 4af564a82f..5497c24280 100644
--- a/lib/vector.c
+++ b/lib/vector.c
@@ -37,6 +37,7 @@ vector vector_init(unsigned int size)
v->alloced = size;
v->active = 0;
+ v->count = 0;
v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size);
return v;
}
@@ -54,6 +55,7 @@ vector vector_copy(vector v)
new->active = v->active;
new->alloced = v->alloced;
+ new->count = v->count;
size = sizeof(void *) * (v->alloced);
new->index = XCALLOC(MTYPE_VECTOR_INDEX, size);
@@ -84,6 +86,9 @@ int vector_empty_slot(vector v)
{
unsigned int i;
+ if (v->active == v->count)
+ return v->active;
+
if (v->active == 0)
return 0;
@@ -102,6 +107,10 @@ int vector_set(vector v, void *val)
i = vector_empty_slot(v);
vector_ensure(v, i);
+ if (v->index[i])
+ v->count--;
+ if (val)
+ v->count++;
v->index[i] = val;
if (v->active <= i)
@@ -115,6 +124,10 @@ int vector_set_index(vector v, unsigned int i, void *val)
{
vector_ensure(v, i);
+ if (v->index[i])
+ v->count--;
+ if (val)
+ v->count++;
v->index[i] = val;
if (v->active <= i)
@@ -123,17 +136,6 @@ int vector_set_index(vector v, unsigned int i, void *val)
return i;
}
-/* Make a specified index slot active and return its address. */
-void **vector_get_index(vector v, unsigned int i)
-{
- vector_ensure(v, i);
-
- if (v->active <= i)
- v->active = i + 1;
-
- return &v->index[i];
-}
-
/* Look up vector. */
void *vector_lookup(vector v, unsigned int i)
{
@@ -155,6 +157,9 @@ void vector_unset(vector v, unsigned int i)
if (i >= v->alloced)
return;
+ if (v->index[i])
+ v->count--;
+
v->index[i] = NULL;
if (i + 1 == v->active) {
@@ -169,6 +174,9 @@ void vector_remove(vector v, unsigned int ix)
if (ix >= v->active)
return;
+ if (v->index[ix])
+ v->count--;
+
int n = (--v->active) - ix;
memmove(&v->index[ix], &v->index[ix + 1], n * sizeof(void *));
@@ -192,6 +200,7 @@ void vector_unset_value(vector v, void *val)
for (i = 0; i < v->active; i++)
if (v->index[i] == val) {
v->index[i] = NULL;
+ v->count--;
break;
}
@@ -201,19 +210,6 @@ void vector_unset_value(vector v, void *val)
while (i && v->index[--i] == NULL);
}
-/* Count the number of not emplty slot. */
-unsigned int vector_count(vector v)
-{
- unsigned int i;
- unsigned count = 0;
-
- for (i = 0; i < v->active; i++)
- if (v->index[i] != NULL)
- count++;
-
- return count;
-}
-
void vector_to_array(vector v, void ***dest, int *argc)
{
*dest = XCALLOC(MTYPE_TMP, sizeof(void *) * v->active);
diff --git a/lib/vector.h b/lib/vector.h
index 845c8d8b04..71c497a1b7 100644
--- a/lib/vector.h
+++ b/lib/vector.h
@@ -32,6 +32,7 @@ extern "C" {
struct _vector {
unsigned int active; /* number of active slots */
unsigned int alloced; /* number of allocated slot */
+ unsigned int count;
void **index; /* index to data */
};
typedef struct _vector *vector;
@@ -54,13 +55,16 @@ extern void vector_ensure(vector v, unsigned int num);
extern int vector_empty_slot(vector v);
extern int vector_set(vector v, void *val);
extern int vector_set_index(vector v, unsigned int i, void *val);
-extern void **vector_get_index(vector v, unsigned int i);
extern void vector_unset(vector v, unsigned int i);
extern void vector_unset_value(vector v, void *val);
extern void vector_remove(vector v, unsigned int ix);
extern void vector_compact(vector v);
-extern unsigned int vector_count(vector v);
+static inline unsigned int vector_count(vector v)
+{
+ return v->count;
+}
+
extern void vector_free(vector v);
extern vector vector_copy(vector v);
diff --git a/lib/vrf.c b/lib/vrf.c
index 198d5253c8..a6250b31a8 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -21,9 +21,6 @@
#include <zebra.h>
-/* for basename */
-#include <libgen.h>
-
#include "if.h"
#include "vrf.h"
#include "vrf_int.h"
@@ -97,28 +94,6 @@ static int vrf_name_compare(const struct vrf *a, const struct vrf *b)
return strcmp(a->name, b->name);
}
-/* if ns_id is different and not VRF_UNKNOWN,
- * then update vrf identifier, and enable VRF
- */
-static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr)
-{
- ns_id_t vrf_id = (vrf_id_t)ns_id;
- vrf_id_t old_vrf_id;
- struct vrf *vrf = (struct vrf *)opaqueptr;
-
- if (!vrf)
- return;
- old_vrf_id = vrf->vrf_id;
- if (vrf_id == vrf->vrf_id)
- return;
- if (vrf->vrf_id != VRF_UNKNOWN)
- RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
- vrf->vrf_id = vrf_id;
- RB_INSERT(vrf_id_head, &vrfs_by_id, vrf);
- if (old_vrf_id == VRF_UNKNOWN)
- vrf_enable(vrf);
-}
-
int vrf_switch_to_netns(vrf_id_t vrf_id)
{
char *name;
@@ -272,32 +247,27 @@ void vrf_delete(struct vrf *vrf)
if (vrf_is_enabled(vrf))
vrf_disable(vrf);
+ if (vrf->vrf_id != VRF_UNKNOWN) {
+ RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
+ vrf->vrf_id = VRF_UNKNOWN;
+ }
+
/* If the VRF is user configured, it'll stick around, just remove
* the ID mapping. Interfaces assigned to this VRF should've been
* removed already as part of the VRF going down.
*/
- if (vrf_is_user_cfged(vrf)) {
- if (vrf->vrf_id != VRF_UNKNOWN) {
- /* Delete any VRF interfaces - should be only
- * the VRF itself, other interfaces should've
- * been moved out of the VRF.
- */
- if_terminate(vrf);
- RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
- vrf->vrf_id = VRF_UNKNOWN;
- }
- vrf->ns_ctxt = NULL;
+ if (vrf_is_user_cfged(vrf))
+ return;
+
+ /* Do not delete the VRF if it has interfaces configured in it. */
+ if (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name))
return;
- }
if (vrf_master.vrf_delete_hook)
(*vrf_master.vrf_delete_hook)(vrf);
QOBJ_UNREG(vrf);
- if_terminate(vrf);
- if (vrf->vrf_id != VRF_UNKNOWN)
- RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
if (vrf->name[0] != '\0')
RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf);
@@ -384,13 +354,6 @@ const char *vrf_id_to_name(vrf_id_t vrf_id)
return VRF_LOGNAME(vrf);
}
-/* Get the data pointer of the specified VRF. If not found, create one. */
-void *vrf_info_get(vrf_id_t vrf_id)
-{
- struct vrf *vrf = vrf_get(vrf_id, NULL);
- return vrf->info;
-}
-
/* Look up the data pointer of the specified VRF. */
void *vrf_info_lookup(vrf_id_t vrf_id)
{
@@ -571,6 +534,7 @@ static void vrf_terminate_single(struct vrf *vrf)
{
/* Clear configured flag and invoke delete. */
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
+ if_terminate(vrf);
vrf_delete(vrf);
}
@@ -598,7 +562,8 @@ void vrf_terminate(void)
/* Finally terminate default VRF */
vrf = vrf_lookup_by_id(VRF_DEFAULT);
- vrf_terminate_single(vrf);
+ if (vrf)
+ vrf_terminate_single(vrf);
}
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
@@ -659,115 +624,6 @@ int vrf_configure_backend(enum vrf_backend_type backend)
return 0;
}
-int vrf_handler_create(struct vty *vty, const char *vrfname,
- struct vrf **vrf)
-{
- struct vrf *vrfp;
- char xpath_list[XPATH_MAXLEN];
- int ret;
-
- if (strlen(vrfname) > VRF_NAMSIZ) {
- if (vty)
- vty_out(vty,
- "%% VRF name %s invalid: length exceeds %d bytes\n",
- vrfname, VRF_NAMSIZ);
- else
- flog_warn(
- EC_LIB_VRF_LENGTH,
- "%% VRF name %s invalid: length exceeds %d bytes",
- vrfname, VRF_NAMSIZ);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (vty) {
- snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH,
- vrfname);
-
- nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL);
- ret = nb_cli_apply_changes_clear_pending(vty, xpath_list);
- if (ret == CMD_SUCCESS) {
- VTY_PUSH_XPATH(VRF_NODE, xpath_list);
- vrfp = vrf_lookup_by_name(vrfname);
- if (vrfp)
- VTY_PUSH_CONTEXT(VRF_NODE, vrfp);
- }
- } else {
- vrfp = vrf_get(VRF_UNKNOWN, vrfname);
-
- if (vrf)
- *vrf = vrfp;
- }
- return CMD_SUCCESS;
-}
-
-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)
-{
- struct ns *ns = NULL;
-
- if (!vrf)
- return CMD_WARNING_CONFIG_FAILED;
- if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) {
- if (vty)
- vty_out(vty,
- "VRF %u is already configured with VRF %s\n",
- vrf->vrf_id, vrf->name);
- else
- zlog_info("VRF %u is already configured with VRF %s",
- vrf->vrf_id, vrf->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (vrf->ns_ctxt != NULL) {
- ns = (struct ns *)vrf->ns_ctxt;
- if (!strcmp(ns->name, pathname)) {
- if (vty)
- vty_out(vty,
- "VRF %u already configured with NETNS %s\n",
- vrf->vrf_id, ns->name);
- else
- zlog_info(
- "VRF %u already configured with NETNS %s",
- vrf->vrf_id, ns->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
- ns = ns_lookup_name(pathname);
- if (ns && ns->vrf_ctxt) {
- struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt;
-
- if (vrf2 == vrf)
- return CMD_SUCCESS;
- if (vty)
- vty_out(vty,
- "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)",
- ns->name, vrf2->vrf_id, vrf2->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
- 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 */
- strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
-
- if (!ns_enable(ns, vrf_update_vrf_id)) {
- if (vty)
- vty_out(vty, "Can not associate NS %u with NETNS %s\n",
- ns->ns_id, ns->name);
- else
- zlog_info("Can not associate NS %u with NETNS %s",
- ns->ns_id, ns->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
/* vrf CLI commands */
DEFUN_NOSH(vrf_exit,
vrf_exit_cmd,
@@ -786,8 +642,29 @@ DEFUN_YANG_NOSH (vrf,
{
int idx_name = 1;
const char *vrfname = argv[idx_name]->arg;
+ char xpath_list[XPATH_MAXLEN];
+ struct vrf *vrf;
+ int ret;
- return vrf_handler_create(vty, vrfname, NULL);
+ if (strlen(vrfname) > VRF_NAMSIZ) {
+ vty_out(vty,
+ "%% VRF name %s invalid: length exceeds %d bytes\n",
+ vrfname, VRF_NAMSIZ);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname);
+
+ nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL);
+ ret = nb_cli_apply_changes_clear_pending(vty, xpath_list);
+ if (ret == CMD_SUCCESS) {
+ VTY_PUSH_XPATH(VRF_NODE, xpath_list);
+ vrf = vrf_lookup_by_name(vrfname);
+ if (vrf)
+ VTY_PUSH_CONTEXT(VRF_NODE, vrf);
+ }
+
+ return ret;
}
DEFUN_YANG (no_vrf,
@@ -814,15 +691,10 @@ DEFUN_YANG (no_vrf,
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
/*
- * Remove the VRF interface config. Currently, we allow to
- * remove only inactive VRFs, so we use VRF_DEFAULT_NAME here,
- * because when the VRF is removed from kernel, the interface
- * is moved to the default VRF. If we ever allow removing
- * active VRFs, this code have to be updated accordingly.
+ * Remove the VRF interface config when removing the VRF.
*/
snprintf(xpath_list, sizeof(xpath_list),
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- vrfname, VRF_DEFAULT_NAME);
+ "/frr-interface:lib/interface[name='%s']", vrfname);
nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL);
}
diff --git a/lib/vrf.h b/lib/vrf.h
index dab83d42da..73e324c152 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -176,8 +176,6 @@ static inline uint32_t vrf_interface_count(struct vrf *vrf)
* Utilities to obtain the user data
*/
-/* Get the data pointer of the specified VRF. If not found, create one. */
-extern void *vrf_info_get(vrf_id_t);
/* Look up the data pointer of the specified VRF. */
extern void *vrf_info_lookup(vrf_id_t);
@@ -301,21 +299,6 @@ extern int vrf_configure_backend(enum vrf_backend_type backend);
extern int vrf_get_backend(void);
extern int vrf_is_backend_netns(void);
-
-/* API to create a VRF. either from vty
- * or through discovery
- */
-extern int vrf_handler_create(struct vty *vty, const char *name,
- struct vrf **vrf);
-
-/* API to associate a VRF with a NETNS.
- * called either from vty or through discovery
- * should be called from zebra only
- */
-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);
-
/* 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 fef16f1ee7..8eaf13619b 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -48,6 +48,7 @@
#include "lib_errors.h"
#include "northbound_cli.h"
#include "printfrr.h"
+#include "json.h"
#include <arpa/telnet.h>
#include <termios.h>
@@ -57,9 +58,12 @@
#endif
DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
+DEFINE_MTYPE_STATIC(LIB, VTY_SERV, "VTY server");
DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer");
DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history");
+DECLARE_DLIST(vtys, struct vty, itm);
+
/* Vty events */
enum event {
VTY_SERV,
@@ -73,17 +77,31 @@ enum event {
#endif /* VTYSH */
};
-static void vty_event_serv(enum event event, int sock);
+PREDECL_DLIST(vtyservs);
+
+struct vty_serv {
+ struct vtyservs_item itm;
+
+ int sock;
+ bool vtysh;
+
+ struct thread *t_accept;
+};
+
+DECLARE_DLIST(vtyservs, struct vty_serv, itm);
+
+static void vty_event_serv(enum event event, struct vty_serv *);
static void vty_event(enum event, struct vty *);
/* Extern host structure from command.c */
extern struct host host;
-/* Vector which store each vty structure. */
-static vector vtyvec;
+/* active listeners */
+static struct vtyservs_head vty_servs[1] = {INIT_DLIST(vty_servs[0])};
-/* Vector for vtysh connections. */
-static vector vtyshvec;
+/* active connections */
+static struct vtys_head vty_sessions[1] = {INIT_DLIST(vty_sessions[0])};
+static struct vtys_head vtysh_sessions[1] = {INIT_DLIST(vtysh_sessions[0])};
/* Vty timeout value. */
static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
@@ -94,9 +112,6 @@ static char *vty_accesslist_name = NULL;
/* Vty access-calss for IPv6. */
static char *vty_ipv6_accesslist_name = NULL;
-/* VTY server thread. */
-static vector Vvty_serv_thread;
-
/* Current directory. */
static char vty_cwd[MAXPATHLEN];
@@ -266,70 +281,28 @@ done:
return len;
}
-static int vty_log_out(struct vty *vty, const char *level,
- const char *proto_str, const char *msg,
- struct timestamp_control *ctl)
+int vty_json(struct vty *vty, struct json_object *json)
{
- int ret;
- int len;
- char buf[1024];
+ const char *text;
- if (!ctl->already_rendered) {
- ctl->len = quagga_timestamp(ctl->precision, ctl->buf,
- sizeof(ctl->buf));
- ctl->already_rendered = 1;
- }
- if (ctl->len + 1 >= sizeof(buf))
- return -1;
- memcpy(buf, ctl->buf, len = ctl->len);
- buf[len++] = ' ';
- buf[len] = '\0';
-
- if (level)
- ret = snprintf(buf + len, sizeof(buf) - len, "%s: %s: ", level,
- proto_str);
- else
- ret = snprintf(buf + len, sizeof(buf) - len, "%s: ", proto_str);
- if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
- return -1;
+ if (!json)
+ return CMD_SUCCESS;
- if (((ret = snprintf(buf + len, sizeof(buf) - len, "%s", msg)) < 0)
- || ((size_t)((len += ret) + 2) > sizeof(buf)))
- return -1;
+ text = json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE);
+ vty_out(vty, "%s\n", text);
+ json_object_free(json);
- buf[len++] = '\r';
- buf[len++] = '\n';
-
- if (write(vty->wfd, buf, len) < 0) {
- if (ERRNO_IO_RETRY(errno))
- /* Kernel buffer is full, probably too much debugging
- output, so just
- drop the data and ignore. */
- return -1;
- /* Fatal I/O error. */
- vty->monitor =
- 0; /* disable monitoring to avoid infinite recursion */
- flog_err(EC_LIB_SOCKET,
- "%s: write failed to vty client fd %d, closing: %s",
- __func__, vty->fd, safe_strerror(errno));
- buffer_reset(vty->obuf);
- buffer_reset(vty->lbuf);
- /* cannot call vty_close, because a parent routine may still try
- to access the vty struct */
- vty->status = VTY_CLOSE;
- shutdown(vty->fd, SHUT_RDWR);
- return -1;
- }
- return 0;
+ return CMD_SUCCESS;
}
/* Output current time to the vty. */
void vty_time_print(struct vty *vty, int cr)
{
- char buf[QUAGGA_TIMESTAMP_LEN];
+ char buf[FRR_TIMESTAMP_LEN];
- if (quagga_timestamp(0, buf, sizeof(buf)) == 0) {
- zlog_info("quagga_timestamp error");
+ if (frr_timestamp(0, buf, sizeof(buf)) == 0) {
+ zlog_info("frr_timestamp error");
return;
}
if (cr)
@@ -480,19 +453,12 @@ static int vty_command(struct vty *vty, char *buf)
cp++;
}
if (cp != NULL && *cp != '\0') {
- unsigned i;
char vty_str[VTY_BUFSIZ];
char prompt_str[VTY_BUFSIZ];
/* format the base vty info */
- snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address);
-
- for (i = 0; i < vector_active(vtyvec); i++)
- if (vty == vector_slot(vtyvec, i)) {
- snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s",
- i, vty->address);
- break;
- }
+ snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", vty->fd,
+ vty->address);
/* format the prompt */
snprintf(prompt_str, sizeof(prompt_str), cmd_prompt(vty->node),
@@ -776,7 +742,7 @@ static void vty_end_config(struct vty *vty)
vty->cp = 0;
}
-/* Delete a charcter at the current point. */
+/* Delete a character at the current point. */
static void vty_delete_char(struct vty *vty)
{
int i;
@@ -1624,13 +1590,14 @@ static struct vty *vty_new_init(int vty_sock)
memset(vty->xpath, 0, sizeof(vty->xpath));
vty->private_config = false;
vty->candidate_config = vty_shared_candidate_config;
- vector_set_index(vtyvec, vty_sock, vty);
vty->status = VTY_NORMAL;
vty->lines = -1;
vty->iac = 0;
vty->iac_sb_in_progress = 0;
vty->sb_len = 0;
+ vtys_add_tail(vty_sessions, vty);
+
return vty;
}
@@ -1788,18 +1755,17 @@ struct vty *vty_stdio(void (*atclose)(int isexit))
/* Accept connection from the network. */
static int vty_accept(struct thread *thread)
{
+ struct vty_serv *vtyserv = THREAD_ARG(thread);
int vty_sock;
union sockunion su;
int ret;
unsigned int on;
- int accept_sock;
+ int accept_sock = vtyserv->sock;
struct prefix p;
struct access_list *acl = NULL;
- accept_sock = THREAD_FD(thread);
-
/* We continue hearing vty socket. */
- vty_event_serv(VTY_SERV, accept_sock);
+ vty_event_serv(VTY_SERV, vtyserv);
memset(&su, 0, sizeof(union sockunion));
@@ -1826,10 +1792,6 @@ static int vty_accept(struct thread *thread)
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
-
- /* continue accepting connections */
- vty_event_serv(VTY_SERV, accept_sock);
-
return 0;
}
}
@@ -1841,10 +1803,6 @@ static int vty_accept(struct thread *thread)
&& (access_list_apply(acl, &p) == FILTER_DENY)) {
zlog_info("Vty connection refused from %pSU", &su);
close(vty_sock);
-
- /* continue accepting connections */
- vty_event_serv(VTY_SERV, accept_sock);
-
return 0;
}
}
@@ -1890,6 +1848,8 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
ainfo_save = ainfo;
do {
+ struct vty_serv *vtyserv;
+
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
continue;
@@ -1915,7 +1875,11 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
continue;
}
- vty_event_serv(VTY_SERV, sock);
+ vtyserv = XCALLOC(MTYPE_VTY_SERV, sizeof(*vtyserv));
+ vtyserv->sock = sock;
+ vtyservs_add_tail(vty_servs, vtyserv);
+
+ vty_event_serv(VTY_SERV, vtyserv);
} while ((ainfo = ainfo->ai_next) != NULL);
freeaddrinfo(ainfo_save);
@@ -1928,6 +1892,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
/* VTY shell UNIX domain socket. */
static void vty_serv_un(const char *path)
{
+ struct vty_serv *vtyserv;
int ret;
int sock, len;
struct sockaddr_un serv;
@@ -1993,22 +1958,26 @@ static void vty_serv_un(const char *path)
}
}
- vty_event_serv(VTYSH_SERV, sock);
+ vtyserv = XCALLOC(MTYPE_VTY_SERV, sizeof(*vtyserv));
+ vtyserv->sock = sock;
+ vtyserv->vtysh = true;
+ vtyservs_add_tail(vty_servs, vtyserv);
+
+ vty_event_serv(VTYSH_SERV, vtyserv);
}
/* #define VTYSH_DEBUG 1 */
static int vtysh_accept(struct thread *thread)
{
- int accept_sock;
+ struct vty_serv *vtyserv = THREAD_ARG(thread);
+ int accept_sock = vtyserv->sock;
int sock;
int client_len;
struct sockaddr_un client;
struct vty *vty;
- accept_sock = THREAD_FD(thread);
-
- vty_event_serv(VTYSH_SERV, accept_sock);
+ vty_event_serv(VTYSH_SERV, vtyserv);
memset(&client, 0, sizeof(struct sockaddr_un));
client_len = sizeof(struct sockaddr_un);
@@ -2041,7 +2010,7 @@ static int vtysh_accept(struct thread *thread)
vty->wfd = sock;
vty->type = VTY_SHELL_SERV;
vty->node = VIEW_NODE;
- vector_set_index(vtyshvec, sock, vty);
+ vtys_add_tail(vtysh_sessions, vty);
vty_event(VTYSH_READ, vty);
@@ -2217,9 +2186,9 @@ void vty_close(struct vty *vty)
/* Unset vector. */
if (vty->fd != -1) {
if (vty->type == VTY_SHELL_SERV)
- vector_unset(vtyshvec, vty->fd);
+ vtys_del(vtysh_sessions, vty);
else
- vector_unset(vtyvec, vty->fd);
+ vtys_del(vty_sessions, vty);
}
if (vty->wfd > 0 && vty->type == VTY_FILE)
@@ -2282,7 +2251,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
vty = vty_new();
/* vty_close won't close stderr; if some config command prints
- * something it'll end up there. (not ideal; it'd be beter if output
+ * something it'll end up there. (not ideal; it'd be better if output
* from a file-load went to logging instead. Also note that if this
* function is called after daemonizing, stderr will be /dev/null.)
*
@@ -2533,52 +2502,6 @@ tmp_free_and_out:
return read_success;
}
-/* Small utility function which output log to the VTY. */
-void vty_log(const char *level, const char *proto_str, const char *msg,
- struct timestamp_control *ctl)
-{
- unsigned int i;
- struct vty *vty;
-
- if (!vtyvec)
- return;
-
- for (i = 0; i < vector_active(vtyvec); i++)
- if ((vty = vector_slot(vtyvec, i)) != NULL)
- if (vty->monitor)
- vty_log_out(vty, level, proto_str, msg, ctl);
-}
-
-/* Async-signal-safe version of vty_log for fixed strings. */
-void vty_log_fixed(char *buf, size_t len)
-{
- unsigned int i;
- struct iovec iov[2];
- char crlf[4] = "\r\n";
-
- /* vty may not have been initialised */
- if (!vtyvec)
- return;
-
- iov[0].iov_base = buf;
- iov[0].iov_len = len;
- iov[1].iov_base = crlf;
- iov[1].iov_len = 2;
-
- for (i = 0; i < vector_active(vtyvec); i++) {
- struct vty *vty;
- if (((vty = vector_slot(vtyvec, i)) != NULL) && vty->monitor)
- /* N.B. We don't care about the return code, since
- process is
- most likely just about to die anyway. */
- if (writev(vty->wfd, iov, 2) == -1) {
- fprintf(stderr, "Failure to writev: %d\n",
- errno);
- exit(-1);
- }
- }
-}
-
static void update_xpath(struct vty *vty, const char *oldpath,
const char *newpath)
{
@@ -2597,21 +2520,11 @@ static void update_xpath(struct vty *vty, const char *oldpath,
void vty_update_xpath(const char *oldpath, const char *newpath)
{
struct vty *vty;
- unsigned int i;
-
- for (i = 0; i < vector_active(vtyshvec); i++) {
- if ((vty = vector_slot(vtyshvec, i)) == NULL)
- continue;
+ frr_each (vtys, vtysh_sessions, vty)
update_xpath(vty, oldpath, newpath);
- }
-
- for (i = 0; i < vector_active(vtyvec); i++) {
- if ((vty = vector_slot(vtyvec, i)) == NULL)
- continue;
-
+ frr_each (vtys, vty_sessions, vty)
update_xpath(vty, oldpath, newpath);
- }
}
int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
@@ -2695,21 +2608,17 @@ int vty_config_node_exit(struct vty *vty)
/* Master of the threads. */
static struct thread_master *vty_master;
-static void vty_event_serv(enum event event, int sock)
+static void vty_event_serv(enum event event, struct vty_serv *vty_serv)
{
- struct thread *vty_serv_thread = NULL;
-
switch (event) {
case VTY_SERV:
- vty_serv_thread = thread_add_read(vty_master, vty_accept,
- NULL, sock, NULL);
- vector_set_index(Vvty_serv_thread, sock, vty_serv_thread);
+ thread_add_read(vty_master, vty_accept, vty_serv,
+ vty_serv->sock, &vty_serv->t_accept);
break;
#ifdef VTYSH
case VTYSH_SERV:
- vty_serv_thread = thread_add_read(vty_master, vtysh_accept,
- NULL, sock, NULL);
- vector_set_index(Vvty_serv_thread, sock, vty_serv_thread);
+ thread_add_read(vty_master, vtysh_accept, vty_serv,
+ vty_serv->sock, &vty_serv->t_accept);
break;
#endif /* VTYSH */
default:
@@ -2761,13 +2670,11 @@ DEFUN_NOSH (config_who,
"who",
"Display who is on vty\n")
{
- unsigned int i;
struct vty *v;
- for (i = 0; i < vector_active(vtyvec); i++)
- if ((v = vector_slot(vtyvec, i)) != NULL)
- vty_out(vty, "%svty[%d] connected from %s.\n",
- v->config ? "*" : " ", i, v->address);
+ frr_each (vtys, vty_sessions, v)
+ vty_out(vty, "%svty[%d] connected from %s.\n",
+ v->config ? "*" : " ", v->fd, v->address);
return CMD_SUCCESS;
}
@@ -3080,25 +2987,14 @@ struct cmd_node vty_node = {
/* Reset all VTY status. */
void vty_reset(void)
{
- unsigned int i;
struct vty *vty;
- struct thread *vty_serv_thread;
-
- for (i = 0; i < vector_active(vtyvec); i++)
- if ((vty = vector_slot(vtyvec, i)) != NULL) {
- buffer_reset(vty->lbuf);
- buffer_reset(vty->obuf);
- vty->status = VTY_CLOSE;
- vty_close(vty);
- }
- for (i = 0; i < vector_active(Vvty_serv_thread); i++)
- if ((vty_serv_thread = vector_slot(Vvty_serv_thread, i))
- != NULL) {
- THREAD_OFF(vty_serv_thread);
- vector_slot(Vvty_serv_thread, i) = NULL;
- close(i);
- }
+ frr_each_safe (vtys, vty_sessions, vty) {
+ buffer_reset(vty->lbuf);
+ buffer_reset(vty->obuf);
+ vty->status = VTY_CLOSE;
+ vty_close(vty);
+ }
vty_timeout_val = VTY_TIMEOUT_DEFAULT;
@@ -3118,7 +3014,7 @@ static void vty_save_cwd(void)
* the whole world is coming down around us
* Hence not worrying about it too much.
*/
- if (!chdir(SYSCONFDIR)) {
+ if (chdir(SYSCONFDIR)) {
flog_err_sys(EC_LIB_SYSTEM_CALL,
"Failure to chdir to %s, errno: %d",
SYSCONFDIR, errno);
@@ -3149,7 +3045,7 @@ int vty_shell_serv(struct vty *vty)
void vty_init_vtysh(void)
{
- vtyvec = vector_init(VECTOR_MIN_SIZE);
+ /* currently nothing to do, but likely to have future use */
}
/* Install vty's own commands like `who' command. */
@@ -3158,16 +3054,10 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging)
/* For further configuration read, preserve current directory. */
vty_save_cwd();
- vtyvec = vector_init(VECTOR_MIN_SIZE);
- vtyshvec = vector_init(VECTOR_MIN_SIZE);
-
vty_master = master_thread;
atexit(vty_stdio_atexit);
- /* Initilize server thread vector. */
- Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE);
-
/* Install bgp top node. */
install_node(&vty_node);
@@ -3202,17 +3092,34 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging)
void vty_terminate(void)
{
+ struct vty *vty;
+ struct vty_serv *vtyserv;
+
memset(vty_cwd, 0x00, sizeof(vty_cwd));
- if (vtyvec && Vvty_serv_thread) {
- vty_reset();
- vector_free(vtyvec);
- vector_free(Vvty_serv_thread);
- vtyvec = NULL;
- Vvty_serv_thread = NULL;
+ vty_reset();
+
+ /* default state of vty_sessions is initialized & empty. */
+ vtys_fini(vty_sessions);
+ vtys_init(vty_sessions);
+
+ /* vty_reset() doesn't close vtysh sessions */
+ frr_each_safe (vtys, vtysh_sessions, vty) {
+ buffer_reset(vty->lbuf);
+ buffer_reset(vty->obuf);
+ vty->status = VTY_CLOSE;
+ vty_close(vty);
}
- if (vtyshvec) {
- vector_free(vtyshvec);
- vtyshvec = NULL;
+
+ vtys_fini(vtysh_sessions);
+ vtys_init(vtysh_sessions);
+
+ while ((vtyserv = vtyservs_pop(vty_servs))) {
+ THREAD_OFF(vtyserv->t_accept);
+ close(vtyserv->sock);
+ XFREE(MTYPE_VTY_SERV, vtyserv);
}
+
+ vtyservs_fini(vty_servs);
+ vtyservs_init(vty_servs);
}
diff --git a/lib/vty.h b/lib/vty.h
index 70ec4fcd84..9ffbce3268 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -39,6 +39,8 @@
extern "C" {
#endif
+struct json_object;
+
#define VTY_BUFSIZ 4096
#define VTY_MAXHIST 20
#define VTY_MAXDEPTH 8
@@ -56,8 +58,12 @@ struct vty_cfg_change {
const char *value;
};
+PREDECL_DLIST(vtys);
+
/* VTY struct. */
struct vty {
+ struct vtys_item itm;
+
/* File descripter of this vty. */
int fd;
@@ -317,7 +323,11 @@ extern struct vty *vty_stdio(void (*atclose)(int isexit));
extern int vty_out(struct vty *, const char *, ...) PRINTFRR(2, 3);
extern void vty_frame(struct vty *, const char *, ...) PRINTFRR(2, 3);
extern void vty_endframe(struct vty *, const char *);
-bool vty_set_include(struct vty *vty, const char *regexp);
+extern bool vty_set_include(struct vty *vty, const char *regexp);
+/* returns CMD_SUCCESS so you can do a one-line "return vty_json(...)"
+ * NULL check and json_object_free() is included.
+ */
+extern int vty_json(struct vty *vty, struct json_object *json);
extern bool vty_read_config(struct nb_config *config, const char *config_file,
char *config_default_dir);
@@ -325,8 +335,6 @@ extern void vty_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *);
extern void vty_close(struct vty *);
extern char *vty_get_cwd(void);
-extern void vty_log(const char *level, const char *proto, const char *msg,
- struct timestamp_control *);
extern void vty_update_xpath(const char *oldpath, const char *newpath);
extern int vty_config_enter(struct vty *vty, bool private_config,
bool exclusive);
@@ -341,10 +349,6 @@ extern void vty_stdio_suspend(void);
extern void vty_stdio_resume(void);
extern void vty_stdio_close(void);
-/* Send a fixed-size message to all vty terminal monitors; this should be
- an async-signal-safe function. */
-extern void vty_log_fixed(char *buf, size_t len);
-
#ifdef __cplusplus
}
#endif
diff --git a/lib/vxlan.h b/lib/vxlan.h
index 62963a6097..220fd8d232 100644
--- a/lib/vxlan.h
+++ b/lib/vxlan.h
@@ -26,7 +26,7 @@
extern "C" {
#endif
-/* EVPN MH DF election alogorithm */
+/* EVPN MH DF election algorithm */
#define EVPN_MH_DF_ALG_SERVICE_CARVING 0
#define EVPN_MH_DF_ALG_HRW 1
#define EVPN_MH_DF_ALG_PREF 2
diff --git a/lib/xref.c b/lib/xref.c
index a41f91a228..0d3549d062 100644
--- a/lib/xref.c
+++ b/lib/xref.c
@@ -35,6 +35,8 @@
struct xref_block *xref_blocks;
static struct xref_block **xref_block_last = &xref_blocks;
+struct xrefdata_uid_head xrefdata_uid = INIT_RBTREE_UNIQ(xrefdata_uid);
+
static void base32(uint8_t **inpos, int *bitpos,
char *out, size_t n_chars)
{
@@ -109,6 +111,8 @@ static void xref_add_one(const struct xref *xref)
base32(&h, &bitpos, &xrefdata->uid[0], 5);
xrefdata->uid[5] = '-';
base32(&h, &bitpos, &xrefdata->uid[6], 5);
+
+ xrefdata_uid_add(&xrefdata_uid, xrefdata);
}
void xref_gcc_workaround(const struct xref *xref)
diff --git a/lib/xref.h b/lib/xref.h
index 6cff1a3769..0e3f00f690 100644
--- a/lib/xref.h
+++ b/lib/xref.h
@@ -22,6 +22,7 @@
#include <limits.h>
#include <errno.h>
#include "compiler.h"
+#include "typesafe.h"
#ifdef __cplusplus
extern "C" {
@@ -63,6 +64,8 @@ struct xref {
/* type-specific bits appended by embedding this struct */
};
+PREDECL_RBTREE_UNIQ(xrefdata_uid);
+
struct xrefdata {
/* pointer back to the const part; this will be initialized at
* program startup by xref_block_add(). (Creating structs with
@@ -88,8 +91,18 @@ struct xrefdata {
uint32_t hashu32[2];
/* -- 32 bytes (on 64bit) -- */
+ struct xrefdata_uid_item xui;
};
+static inline int xrefdata_uid_cmp(const struct xrefdata *a,
+ const struct xrefdata *b)
+{
+ return strcmp(a->uid, b->uid);
+}
+
+DECLARE_RBTREE_UNIQ(xrefdata_uid, struct xrefdata, xui, xrefdata_uid_cmp);
+extern struct xrefdata_uid_head xrefdata_uid;
+
/* linker "magic" is used to create an array of pointers to struct xref.
* the result is a contiguous block of pointers, each pointing to an xref
* somewhere in the code. The linker gives us start and end pointers, we
diff --git a/lib/yang.h b/lib/yang.h
index d4517f969a..d625b24f6a 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -183,7 +183,7 @@ extern int yang_snodes_iterate_subtree(const struct lysc_node *snode,
void *arg);
/*
- * Iterate over all libyang schema nodes from all loeaded modules of from the
+ * Iterate over all libyang schema nodes from all loaded modules of the
* given YANG module.
*
* module
diff --git a/lib/zclient.c b/lib/zclient.c
index dde60a6c90..000dcaac8f 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -66,7 +66,8 @@ static int zclient_debug;
/* Allocate zclient structure. */
struct zclient *zclient_new(struct thread_master *master,
- struct zclient_options *opt)
+ struct zclient_options *opt,
+ zclient_handler *const *handlers, size_t n_handlers)
{
struct zclient *zclient;
size_t stream_size =
@@ -79,6 +80,9 @@ struct zclient *zclient_new(struct thread_master *master,
zclient->wb = buffer_new(0);
zclient->master = master;
+ zclient->handlers = handlers;
+ zclient->n_handlers = n_handlers;
+
zclient->receive_notify = opt->receive_notify;
zclient->synchronous = opt->synchronous;
@@ -450,7 +454,7 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient,
p.prefix = *sid;
api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_BGP;
+ api.type = zclient->redist_default;
api.instance = 0;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, &p, sizeof(p));
@@ -765,15 +769,17 @@ static int zclient_connect(struct thread *t)
enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command,
const struct prefix *p,
- bool exact_match, vrf_id_t vrf_id)
+ bool connected,
+ bool resolve_via_def, vrf_id_t vrf_id)
{
struct stream *s;
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, command, vrf_id);
- stream_putc(s, (exact_match) ? 1 : 0);
-
+ stream_putc(s, (connected) ? 1 : 0);
+ stream_putc(s, (resolve_via_def) ? 1 : 0);
+ stream_putw(s, SAFI_UNICAST);
stream_putw(s, PREFIX_FAMILY(p));
stream_putc(s, p->prefixlen);
switch (PREFIX_FAMILY(p)) {
@@ -1925,6 +1931,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->safi);
STREAM_GETW(s, nhr->prefix.family);
STREAM_GETC(s, nhr->prefix.prefixlen);
switch (nhr->prefix.family) {
@@ -2096,7 +2103,7 @@ stream_failure:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Harware Address Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Hardware Address if HW lenght different from 0 |
+ * | Hardware Address if HW length different from 0 |
* | ... max INTERFACE_HWADDR_MAX |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Link_params? | Whether a link-params follows: 1 or 0.
@@ -2106,7 +2113,7 @@ stream_failure:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-static int zclient_vrf_add(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_vrf_add(ZAPI_CALLBACK_ARGS)
{
struct vrf *vrf;
char vrfname_tmp[VRF_NAMSIZ + 1] = {};
@@ -2138,7 +2145,7 @@ stream_failure:
return -1;
}
-static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_vrf_delete(ZAPI_CALLBACK_ARGS)
{
struct vrf *vrf;
@@ -2151,29 +2158,32 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id)
* no point in attempting to delete it.
*/
if (!vrf)
- return;
+ return 0;
vrf_delete(vrf);
+ return 0;
}
-static int zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_interface_add(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
char ifname_tmp[INTERFACE_NAMSIZ + 1] = {};
struct stream *s = zclient->ibuf;
+ struct vrf *vrf;
/* Read interface name. */
STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ);
/* Lookup/create interface by name. */
- if (!vrf_get(vrf_id, NULL)) {
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (!vrf) {
zlog_debug(
"Rx'd interface add from Zebra, but VRF %u does not exist",
vrf_id);
return -1;
}
- ifp = if_get_by_name(ifname_tmp, vrf_id);
+ ifp = if_get_by_name(ifname_tmp, vrf_id, vrf->name);
zebra_interface_if_set_value(s, ifp);
@@ -2214,7 +2224,7 @@ stream_failure:
return NULL;
}
-static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_interface_delete(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
struct stream *s = zclient->ibuf;
@@ -2222,13 +2232,13 @@ static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id)
ifp = zebra_interface_state_read(s, vrf_id);
if (ifp == NULL)
- return;
+ return 0;
if_destroy_via_zapi(ifp);
- return;
+ return 0;
}
-static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_interface_up(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
struct stream *s = zclient->ibuf;
@@ -2236,12 +2246,13 @@ static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id)
ifp = zebra_interface_state_read(s, vrf_id);
if (!ifp)
- return;
+ return 0;
if_up_via_zapi(ifp);
+ return 0;
}
-static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id)
+static int zclient_interface_down(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
struct stream *s = zclient->ibuf;
@@ -2249,12 +2260,13 @@ static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id)
ifp = zebra_interface_state_read(s, vrf_id);
if (!ifp)
- return;
+ return 0;
if_down_via_zapi(ifp);
+ return 0;
}
-static void zclient_handle_error(ZAPI_CALLBACK_ARGS)
+static int zclient_handle_error(ZAPI_CALLBACK_ARGS)
{
enum zebra_error_types error;
struct stream *s = zclient->ibuf;
@@ -2263,6 +2275,7 @@ static void zclient_handle_error(ZAPI_CALLBACK_ARGS)
if (zclient->handle_error)
(*zclient->handle_error)(error);
+ return 0;
}
static int link_params_set_value(struct stream *s, struct if_link_params *iflp)
@@ -2435,7 +2448,7 @@ size_t zebra_interface_link_params_write(struct stream *s,
}
/*
- * format of message for address additon is:
+ * format of message for address addition is:
* 0
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
@@ -2700,9 +2713,9 @@ static int zclient_read_sync_response(struct zclient *zclient,
return 0;
}
/**
- * Connect to label manager in a syncronous way
+ * Connect to label manager in a synchronous way
*
- * It first writes the request to zcient output buffer and then
+ * It first writes the request to zclient output buffer and then
* immediately reads the answer from the input buffer.
*
* @param zclient Zclient used to connect to label manager (zebra)
@@ -2795,7 +2808,7 @@ stream_failure:
}
/**
- * Function to request a srv6-locator chunk in an Asyncronous way
+ * Function to request a srv6-locator chunk in an asynchronous way
*
* @param zclient Zclient used to connect to table manager (zebra)
* @param locator_name Name of SRv6-locator
@@ -2905,9 +2918,9 @@ enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient,
}
/**
- * Function to request a label chunk in a syncronous way
+ * Function to request a label chunk in a synchronous way
*
- * It first writes the request to zlcient output buffer and then
+ * It first writes the request to zclient output buffer and then
* immediately reads the answer from the input buffer.
*
* @param zclient Zclient used to connect to label manager (zebra)
@@ -3082,9 +3095,9 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
}
/**
- * Connect to table manager in a syncronous way
+ * Connect to table manager in a synchronous way
*
- * It first writes the request to zcient output buffer and then
+ * It first writes the request to zclient output buffer and then
* immediately reads the answer from the input buffer.
*
* @param zclient Zclient used to connect to table manager (zebra)
@@ -3141,7 +3154,7 @@ stream_failure:
}
/**
- * Function to request a table chunk in a syncronous way
+ * Function to request a table chunk in a synchronous way
*
* It first writes the request to zclient output buffer and then
* immediately reads the answer from the input buffer.
@@ -3580,7 +3593,7 @@ stream_failure:
return -1;
}
-static void zclient_capability_decode(ZAPI_CALLBACK_ARGS)
+static int zclient_capability_decode(ZAPI_CALLBACK_ARGS)
{
struct zclient_capabilities cap;
struct stream *s = zclient->ibuf;
@@ -3607,7 +3620,7 @@ static void zclient_capability_decode(ZAPI_CALLBACK_ARGS)
(*zclient->zebra_capabilities)(&cap);
stream_failure:
- return;
+ return 0;
}
enum zclient_send_status zclient_send_mlag_register(struct zclient *client,
@@ -3646,24 +3659,6 @@ enum zclient_send_status zclient_send_mlag_data(struct zclient *client,
return zclient_send_message(client);
}
-static void zclient_mlag_process_up(ZAPI_CALLBACK_ARGS)
-{
- if (zclient->mlag_process_up)
- (*zclient->mlag_process_up)();
-}
-
-static void zclient_mlag_process_down(ZAPI_CALLBACK_ARGS)
-{
- if (zclient->mlag_process_down)
- (*zclient->mlag_process_down)();
-}
-
-static void zclient_mlag_handle_msg(ZAPI_CALLBACK_ARGS)
-{
- if (zclient->mlag_handle_msg)
- (*zclient->mlag_handle_msg)(zclient->ibuf, length);
-}
-
/*
* Send an OPAQUE message, contents opaque to zebra. The message header
* is a message subtype.
@@ -3853,6 +3848,24 @@ stream_failure:
return -1;
}
+static zclient_handler *const lib_handlers[] = {
+ /* fundamentals */
+ [ZEBRA_CAPABILITIES] = zclient_capability_decode,
+ [ZEBRA_ERROR] = zclient_handle_error,
+
+ /* VRF & interface code is shared in lib */
+ [ZEBRA_VRF_ADD] = zclient_vrf_add,
+ [ZEBRA_VRF_DELETE] = zclient_vrf_delete,
+ [ZEBRA_INTERFACE_ADD] = zclient_interface_add,
+ [ZEBRA_INTERFACE_DELETE] = zclient_interface_delete,
+ [ZEBRA_INTERFACE_UP] = zclient_interface_up,
+ [ZEBRA_INTERFACE_DOWN] = zclient_interface_down,
+
+ /* BFD */
+ [ZEBRA_BFD_DEST_REPLAY] = zclient_bfd_session_replay,
+ [ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update,
+};
+
/* Zebra client message read function. */
static int zclient_read(struct thread *thread)
{
@@ -3952,290 +3965,10 @@ static int zclient_read(struct thread *thread)
zlog_debug("zclient %p command %s VRF %u", zclient,
zserv_command_string(command), vrf_id);
- switch (command) {
- case ZEBRA_CAPABILITIES:
- zclient_capability_decode(command, zclient, length, vrf_id);
- break;
- case ZEBRA_ROUTER_ID_UPDATE:
- if (zclient->router_id_update)
- (*zclient->router_id_update)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_VRF_ADD:
- zclient_vrf_add(zclient, vrf_id);
- break;
- case ZEBRA_VRF_DELETE:
- zclient_vrf_delete(zclient, vrf_id);
- break;
- case ZEBRA_INTERFACE_ADD:
- zclient_interface_add(zclient, vrf_id);
- break;
- case ZEBRA_INTERFACE_DELETE:
- zclient_interface_delete(zclient, vrf_id);
- break;
- case ZEBRA_INTERFACE_ADDRESS_ADD:
- if (zclient->interface_address_add)
- (*zclient->interface_address_add)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_INTERFACE_ADDRESS_DELETE:
- if (zclient->interface_address_delete)
- (*zclient->interface_address_delete)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_INTERFACE_BFD_DEST_UPDATE:
- if (zclient->interface_bfd_dest_update)
- (*zclient->interface_bfd_dest_update)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_INTERFACE_NBR_ADDRESS_ADD:
- if (zclient->interface_nbr_address_add)
- (*zclient->interface_nbr_address_add)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_INTERFACE_NBR_ADDRESS_DELETE:
- if (zclient->interface_nbr_address_delete)
- (*zclient->interface_nbr_address_delete)(
- command, zclient, length, vrf_id);
- break;
- case ZEBRA_INTERFACE_UP:
- zclient_interface_up(zclient, vrf_id);
- break;
- case ZEBRA_INTERFACE_DOWN:
- zclient_interface_down(zclient, vrf_id);
- break;
- case ZEBRA_INTERFACE_VRF_UPDATE:
- if (zclient->interface_vrf_update)
- (*zclient->interface_vrf_update)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_NEXTHOP_UPDATE:
- if (zclient_debug)
- zlog_debug("zclient rcvd nexthop update");
- if (zclient->nexthop_update)
- (*zclient->nexthop_update)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_IMPORT_CHECK_UPDATE:
- if (zclient_debug)
- zlog_debug("zclient rcvd import check update");
- if (zclient->import_check_update)
- (*zclient->import_check_update)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_BFD_DEST_REPLAY:
- if (zclient->bfd_dest_replay)
- (*zclient->bfd_dest_replay)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_REDISTRIBUTE_ROUTE_ADD:
- if (zclient->redistribute_route_add)
- (*zclient->redistribute_route_add)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_REDISTRIBUTE_ROUTE_DEL:
- if (zclient->redistribute_route_del)
- (*zclient->redistribute_route_del)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_INTERFACE_LINK_PARAMS:
- if (zclient->interface_link_params)
- (*zclient->interface_link_params)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_FEC_UPDATE:
- if (zclient_debug)
- zlog_debug("zclient rcvd fec update");
- if (zclient->fec_update)
- (*zclient->fec_update)(command, zclient, length);
- break;
- case ZEBRA_LOCAL_ES_ADD:
- if (zclient->local_es_add)
- (*zclient->local_es_add)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_LOCAL_ES_DEL:
- if (zclient->local_es_del)
- (*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,
- vrf_id);
- break;
- case ZEBRA_VNI_DEL:
- if (zclient->local_vni_del)
- (*zclient->local_vni_del)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_L3VNI_ADD:
- if (zclient->local_l3vni_add)
- (*zclient->local_l3vni_add)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_L3VNI_DEL:
- if (zclient->local_l3vni_del)
- (*zclient->local_l3vni_del)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_MACIP_ADD:
- if (zclient->local_macip_add)
- (*zclient->local_macip_add)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_MACIP_DEL:
- if (zclient->local_macip_del)
- (*zclient->local_macip_del)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_IP_PREFIX_ROUTE_ADD:
- if (zclient->local_ip_prefix_add)
- (*zclient->local_ip_prefix_add)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_IP_PREFIX_ROUTE_DEL:
- if (zclient->local_ip_prefix_del)
- (*zclient->local_ip_prefix_del)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_PW_STATUS_UPDATE:
- if (zclient->pw_status_update)
- (*zclient->pw_status_update)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_ROUTE_NOTIFY_OWNER:
- if (zclient->route_notify_owner)
- (*zclient->route_notify_owner)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_RULE_NOTIFY_OWNER:
- if (zclient->rule_notify_owner)
- (*zclient->rule_notify_owner)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_NHG_NOTIFY_OWNER:
- if (zclient->nhg_notify_owner)
- (*zclient->nhg_notify_owner)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_GET_LABEL_CHUNK:
- if (zclient->label_chunk)
- (*zclient->label_chunk)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_IPSET_NOTIFY_OWNER:
- if (zclient->ipset_notify_owner)
- (*zclient->ipset_notify_owner)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_IPSET_ENTRY_NOTIFY_OWNER:
- if (zclient->ipset_entry_notify_owner)
- (*zclient->ipset_entry_notify_owner)(command,
- zclient, length,
- vrf_id);
- break;
- case ZEBRA_IPTABLE_NOTIFY_OWNER:
- if (zclient->iptable_notify_owner)
- (*zclient->iptable_notify_owner)(command,
- zclient, length,
- vrf_id);
- break;
- case ZEBRA_VXLAN_SG_ADD:
- if (zclient->vxlan_sg_add)
- (*zclient->vxlan_sg_add)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_VXLAN_SG_DEL:
- if (zclient->vxlan_sg_del)
- (*zclient->vxlan_sg_del)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_MLAG_PROCESS_UP:
- zclient_mlag_process_up(command, zclient, length, vrf_id);
- break;
- case ZEBRA_MLAG_PROCESS_DOWN:
- zclient_mlag_process_down(command, zclient, length, vrf_id);
- break;
- case ZEBRA_MLAG_FORWARD_MSG:
- zclient_mlag_handle_msg(command, zclient, length, vrf_id);
- break;
- case ZEBRA_SRV6_LOCATOR_ADD:
- if (zclient->srv6_locator_add)
- (*zclient->srv6_locator_add)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_SRV6_LOCATOR_DELETE:
- if (zclient->srv6_locator_delete)
- (*zclient->srv6_locator_delete)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK:
- if (zclient->process_srv6_locator_chunk)
- (*zclient->process_srv6_locator_chunk)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_ERROR:
- zclient_handle_error(command, zclient, length, vrf_id);
- break;
- case ZEBRA_OPAQUE_MESSAGE:
- if (zclient->opaque_msg_handler)
- (*zclient->opaque_msg_handler)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_OPAQUE_REGISTER:
- if (zclient->opaque_register_handler)
- (*zclient->opaque_register_handler)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_OPAQUE_UNREGISTER:
- if (zclient->opaque_unregister_handler)
- (*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);
- break;
- case ZEBRA_CLIENT_CLOSE_NOTIFY:
- if (zclient->zebra_client_close_notify)
- (*zclient->zebra_client_close_notify)(command, zclient,
- length, vrf_id);
- break;
- case ZEBRA_NHRP_NEIGH_ADDED:
- if (zclient->neighbor_added)
- (*zclient->neighbor_added)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_NHRP_NEIGH_REMOVED:
- if (zclient->neighbor_removed)
- (*zclient->neighbor_removed)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_NHRP_NEIGH_GET:
- if (zclient->neighbor_get)
- (*zclient->neighbor_get)(command, zclient, length,
- vrf_id);
- break;
- case ZEBRA_GRE_UPDATE:
- if (zclient->gre_update)
- (*zclient->gre_update)(command, zclient,
- length, vrf_id);
- break;
- default:
- break;
- }
+ if (command < array_size(lib_handlers) && lib_handlers[command])
+ lib_handlers[command](command, zclient, length, vrf_id);
+ if (command < zclient->n_handlers && zclient->handlers[command])
+ zclient->handlers[command](command, zclient, length, vrf_id);
if (zclient->sock < 0)
/* Connection was closed during packet processing. */
@@ -4339,11 +4072,12 @@ enum zclient_send_status zclient_interface_set_master(struct zclient *client,
s = client->obuf;
stream_reset(s);
- zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id);
+ zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER,
+ master->vrf->vrf_id);
- stream_putl(s, master->vrf_id);
+ stream_putl(s, master->vrf->vrf_id);
stream_putl(s, master->ifindex);
- stream_putl(s, slave->vrf_id);
+ stream_putl(s, slave->vrf->vrf_id);
stream_putl(s, slave->ifindex);
stream_putw_at(s, 0, stream_get_endp(s));
@@ -4430,7 +4164,7 @@ zclient_send_neigh_discovery_req(struct zclient *zclient,
s = zclient->obuf;
stream_reset(s);
- zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf_id);
+ zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf->vrf_id);
stream_putl(s, ifp->ifindex);
stream_putc(s, p->family);
@@ -4520,7 +4254,7 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in,
{
int ret = 0;
- zclient_create_header(s, cmd, ifp->vrf_id);
+ zclient_create_header(s, cmd, ifp->vrf->vrf_id);
stream_putc(s, sockunion_family(in));
stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in));
if (out && sockunion_family(out) != AF_UNSPEC) {
@@ -4564,9 +4298,7 @@ int zclient_send_zebra_gre_request(struct zclient *client,
}
s = client->obuf;
stream_reset(s);
- zclient_create_header(s,
- ZEBRA_GRE_GET,
- ifp->vrf_id);
+ zclient_create_header(s, ZEBRA_GRE_GET, ifp->vrf->vrf_id);
stream_putl(s, ifp->ifindex);
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(client);
diff --git a/lib/zclient.h b/lib/zclient.h
index f9438d5db7..ca62b1afeb 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -21,6 +21,8 @@
#ifndef _ZEBRA_ZCLIENT_H
#define _ZEBRA_ZCLIENT_H
+struct zclient;
+
/* For struct zapi_route. */
#include "prefix.h"
#include "ipaddr.h"
@@ -126,9 +128,6 @@ typedef enum {
ZEBRA_INTERFACE_NBR_ADDRESS_ADD,
ZEBRA_INTERFACE_NBR_ADDRESS_DELETE,
ZEBRA_INTERFACE_BFD_DEST_UPDATE,
- ZEBRA_IMPORT_ROUTE_REGISTER,
- ZEBRA_IMPORT_ROUTE_UNREGISTER,
- ZEBRA_IMPORT_CHECK_UPDATE,
ZEBRA_BFD_DEST_REGISTER,
ZEBRA_BFD_DEST_DEREGISTER,
ZEBRA_BFD_DEST_UPDATE,
@@ -287,12 +286,20 @@ struct zapi_cap {
vrf_id_t vrf_id;
};
+/* clang-format off */
+#define ZAPI_CALLBACK_ARGS \
+ int cmd, struct zclient *zclient, uint16_t length, vrf_id_t vrf_id
+
+/* function-type typedef (pointer not included) */
+typedef int (zclient_handler)(ZAPI_CALLBACK_ARGS);
+/* clang-format on */
+
/* Structure for the zebra client. */
struct zclient {
/* The thread master we schedule ourselves on */
struct thread_master *master;
- /* Priviledges to change socket values */
+ /* Privileges to change socket values */
struct zebra_privs_t *privs;
/* Do we care about failure events for route install? */
@@ -301,6 +308,9 @@ struct zclient {
/* Is this a synchronous client? */
bool synchronous;
+ /* BFD enabled with bfd_protocol_integration_init() */
+ bool bfd_integration;
+
/* Session id (optional) to support clients with multiple sessions */
uint32_t session_id;
@@ -332,16 +342,15 @@ struct zclient {
struct redist_proto mi_redist[AFI_MAX][ZEBRA_ROUTE_MAX];
vrf_bitmap_t redist[AFI_MAX][ZEBRA_ROUTE_MAX];
- /* Redistribute defauilt. */
+ /* Redistribute default. */
vrf_bitmap_t default_information[AFI_MAX];
-#define ZAPI_CALLBACK_ARGS \
- int cmd, struct zclient *zclient, uint16_t length, vrf_id_t vrf_id
-
/* Pointer to the callback functions. */
void (*zebra_connected)(struct zclient *);
void (*zebra_capabilities)(struct zclient_capabilities *cap);
+ int (*handle_error)(enum zebra_error_types error);
+
/*
* When the zclient attempts to write the stream data to
* it's named pipe to/from zebra, we may have a situation
@@ -353,62 +362,15 @@ struct zclient {
* more data.
*/
void (*zebra_buffer_write_ready)(void);
- int (*router_id_update)(ZAPI_CALLBACK_ARGS);
- int (*interface_address_add)(ZAPI_CALLBACK_ARGS);
- int (*interface_address_delete)(ZAPI_CALLBACK_ARGS);
- int (*interface_link_params)(ZAPI_CALLBACK_ARGS);
- int (*interface_bfd_dest_update)(ZAPI_CALLBACK_ARGS);
- int (*interface_nbr_address_add)(ZAPI_CALLBACK_ARGS);
- int (*interface_nbr_address_delete)(ZAPI_CALLBACK_ARGS);
- int (*interface_vrf_update)(ZAPI_CALLBACK_ARGS);
- int (*nexthop_update)(ZAPI_CALLBACK_ARGS);
- int (*import_check_update)(ZAPI_CALLBACK_ARGS);
- int (*bfd_dest_replay)(ZAPI_CALLBACK_ARGS);
- int (*redistribute_route_add)(ZAPI_CALLBACK_ARGS);
- int (*redistribute_route_del)(ZAPI_CALLBACK_ARGS);
- 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);
- int (*local_l3vni_del)(ZAPI_CALLBACK_ARGS);
- void (*local_ip_prefix_add)(ZAPI_CALLBACK_ARGS);
- void (*local_ip_prefix_del)(ZAPI_CALLBACK_ARGS);
- int (*local_macip_add)(ZAPI_CALLBACK_ARGS);
- int (*local_macip_del)(ZAPI_CALLBACK_ARGS);
- int (*pw_status_update)(ZAPI_CALLBACK_ARGS);
- int (*route_notify_owner)(ZAPI_CALLBACK_ARGS);
- int (*rule_notify_owner)(ZAPI_CALLBACK_ARGS);
- void (*label_chunk)(ZAPI_CALLBACK_ARGS);
- int (*ipset_notify_owner)(ZAPI_CALLBACK_ARGS);
- int (*ipset_entry_notify_owner)(ZAPI_CALLBACK_ARGS);
- int (*iptable_notify_owner)(ZAPI_CALLBACK_ARGS);
- int (*vxlan_sg_add)(ZAPI_CALLBACK_ARGS);
- int (*vxlan_sg_del)(ZAPI_CALLBACK_ARGS);
- int (*mlag_process_up)(void);
- int (*mlag_process_down)(void);
- int (*mlag_handle_msg)(struct stream *msg, int len);
- int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS);
- int (*srv6_locator_add)(ZAPI_CALLBACK_ARGS);
- int (*srv6_locator_delete)(ZAPI_CALLBACK_ARGS);
- int (*srv6_function_add)(ZAPI_CALLBACK_ARGS);
- int (*srv6_function_delete)(ZAPI_CALLBACK_ARGS);
- void (*process_srv6_locator_chunk)(ZAPI_CALLBACK_ARGS);
- int (*handle_error)(enum zebra_error_types error);
- 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);
- int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS);
- void (*neighbor_added)(ZAPI_CALLBACK_ARGS);
- void (*neighbor_removed)(ZAPI_CALLBACK_ARGS);
- void (*neighbor_get)(ZAPI_CALLBACK_ARGS);
- void (*gre_update)(ZAPI_CALLBACK_ARGS);
+
+ zclient_handler *const *handlers;
+ size_t n_handlers;
};
+/* lib handlers added in bfd.c */
+extern int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS);
+extern int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS);
+
/* Zebra API message flag. */
#define ZAPI_MESSAGE_NEXTHOP 0x01
#define ZAPI_MESSAGE_DISTANCE 0x02
@@ -897,7 +859,9 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in,
extern uint32_t zclient_get_nhg_start(uint32_t proto);
extern struct zclient *zclient_new(struct thread_master *m,
- struct zclient_options *opt);
+ struct zclient_options *opt,
+ zclient_handler *const *handlers,
+ size_t n_handlers);
extern void zclient_init(struct zclient *, int, unsigned short,
struct zebra_privs_t *privs);
@@ -1107,7 +1071,7 @@ extern enum zclient_send_status zclient_route_send(uint8_t, struct zclient *,
struct zapi_route *);
extern enum zclient_send_status
zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p,
- bool exact_match, vrf_id_t vrf_id);
+ bool connected, bool resolve_via_default, 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_message);
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
diff --git a/lib/zebra.h b/lib/zebra.h
index 6a02dcb922..c9794352c7 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -383,6 +383,9 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32
+/* Name of hook calls */
+#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/zlog.c b/lib/zlog.c
index 6fd52cae62..1b0751559d 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -47,12 +47,19 @@
#include <mach/mach_traps.h>
#endif
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <dlfcn.h>
+#endif
+
#include "memory.h"
#include "atomlist.h"
#include "printfrr.h"
#include "frrcu.h"
#include "zlog.h"
#include "libfrr_trace.h"
+#include "thread.h"
DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message");
DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer");
@@ -508,6 +515,87 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref,
XFREE(MTYPE_LOG_MESSAGE, msg->text);
}
+static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio)
+{
+ struct thread *tc = pthread_getspecific(thread_current);
+ const char *uid = xref->xref.xrefdata->uid;
+ bool found_thread = false;
+
+ zlog(prio, "| (%s) message in thread %jd, at %s(), %s:%d", uid,
+ zlog_gettid(), xref->xref.func, xref->xref.file, xref->xref.line);
+
+#ifdef HAVE_LIBUNWIND
+ const char *threadfunc = tc ? tc->xref->funcname : NULL;
+ bool found_caller = false;
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_word_t ip, off, sp;
+ Dl_info dlinfo;
+
+ unw_getcontext(&uc);
+
+ unw_init_local(&cursor, &uc);
+ while (unw_step(&cursor) > 0) {
+ char buf[96], name[128] = "?";
+ bool is_thread = false;
+
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ if (unw_is_signal_frame(&cursor))
+ zlog(prio, "| (%s) ---- signal ----", uid);
+
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) {
+ if (!strcmp(buf, xref->xref.func))
+ found_caller = true;
+ if (threadfunc && !strcmp(buf, threadfunc))
+ found_thread = is_thread = true;
+
+ snprintf(name, sizeof(name), "%s+%#lx", buf, (long)off);
+ }
+
+ if (!found_caller)
+ continue;
+
+ if (dladdr((void *)ip, &dlinfo))
+ zlog(prio, "| (%s) %-36s %16lx+%08lx %16lx %s", uid,
+ name, (long)dlinfo.dli_fbase,
+ (long)ip - (long)dlinfo.dli_fbase, (long)sp,
+ dlinfo.dli_fname);
+ else
+ zlog(prio, "| (%s) %-36s %16lx %16lx", uid, name,
+ (long)ip, (long)sp);
+
+ if (is_thread)
+ zlog(prio, "| (%s) ^- scheduled from %s(), %s:%u", uid,
+ tc->xref->xref.func, tc->xref->xref.file,
+ tc->xref->xref.line);
+ }
+#elif defined(HAVE_GLIBC_BACKTRACE)
+ void *frames[64];
+ char **names = NULL;
+ int n_frames, i;
+
+ n_frames = backtrace(frames, array_size(frames));
+ if (n_frames < 0)
+ n_frames = 0;
+ if (n_frames)
+ names = backtrace_symbols(frames, n_frames);
+
+ for (i = 0; i < n_frames; i++) {
+ void *retaddr = frames[i];
+ char *loc = names[i];
+
+ zlog(prio, "| (%s) %16lx %-36s", uid, (long)retaddr, loc);
+ }
+ free(names);
+#endif
+ if (!found_thread && tc)
+ zlog(prio, "| (%s) scheduled from %s(), %s:%u", uid,
+ tc->xref->xref.func, tc->xref->xref.file,
+ tc->xref->xref.line);
+}
+
void vzlogx(const struct xref_logmsg *xref, int prio,
const char *fmt, va_list ap)
{
@@ -545,6 +633,15 @@ void vzlogx(const struct xref_logmsg *xref, int prio,
vzlog_tls(zlog_tls, xref, prio, fmt, ap);
else
vzlog_notls(xref, prio, fmt, ap);
+
+ if (xref) {
+ struct xrefdata_logmsg *xrdl;
+
+ xrdl = container_of(xref->xref.xrefdata, struct xrefdata_logmsg,
+ xrefdata);
+ if (xrdl->fl_print_bt)
+ zlog_backtrace_msg(xref, prio);
+ }
}
void zlog_sigsafe(const char *text, size_t len)
diff --git a/lib/zlog.h b/lib/zlog.h
index d9c8952ac5..6e84fe8923 100644
--- a/lib/zlog.h
+++ b/lib/zlog.h
@@ -54,10 +54,14 @@ struct xref_logmsg {
const char *args;
};
+/* whether flag was added in config mode or enable mode */
+#define LOGMSG_FLAG_EPHEMERAL (1 << 0)
+#define LOGMSG_FLAG_PERSISTENT (1 << 1)
+
struct xrefdata_logmsg {
struct xrefdata xrefdata;
- /* nothing more here right now */
+ uint8_t fl_print_bt;
};
/* These functions are set up to write to stdout/stderr without explicit
@@ -94,15 +98,19 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
#define _zlog_ecref(ec_, prio, msg, ...) \
do { \
- static struct xrefdata _xrefdata = { \
- .xref = NULL, \
- .uid = {}, \
- .hashstr = (msg), \
- .hashu32 = {(prio), (ec_)}, \
+ static struct xrefdata_logmsg _xrefdata = { \
+ .xrefdata = \
+ { \
+ .xref = NULL, \
+ .uid = {}, \
+ .hashstr = (msg), \
+ .hashu32 = {(prio), (ec_)}, \
+ }, \
}; \
static const struct xref_logmsg _xref __attribute__( \
(used)) = { \
- .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \
+ .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \
+ __func__), \
.fmtstring = (msg), \
.priority = (prio), \
.ec = (ec_), \