summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agentx.c2
-rw-r--r--lib/bfd.c103
-rw-r--r--lib/bfd.h53
-rw-r--r--lib/command.c81
-rw-r--r--lib/command.h1
-rw-r--r--lib/command_lex.l2
-rw-r--r--lib/command_parse.y2
-rw-r--r--lib/defaults.c2
-rw-r--r--lib/filter.c5
-rw-r--r--lib/filter_nb.c5
-rw-r--r--lib/frr_pthread.c3
-rw-r--r--lib/lib_errors.c12
-rw-r--r--lib/lib_errors.h3
-rw-r--r--lib/libfrr.c14
-rw-r--r--lib/libfrr.h8
-rw-r--r--lib/log_vty.c10
-rw-r--r--lib/module.c2
-rw-r--r--lib/northbound_cli.c2
-rw-r--r--lib/northbound_confd.c2
-rw-r--r--lib/northbound_grpc.cpp2
-rw-r--r--lib/northbound_sysrepo.c6
-rw-r--r--lib/pid_output.c2
-rw-r--r--lib/sha256.c4
-rw-r--r--lib/sigevent.c14
-rw-r--r--lib/sockopt.c10
-rw-r--r--lib/subdir.am16
-rw-r--r--lib/thread.c71
-rw-r--r--lib/thread.h2
-rw-r--r--lib/version.h.in2
-rw-r--r--lib/vty.c14
-rw-r--r--lib/xref.h18
-rw-r--r--lib/zclient.h23
-rw-r--r--lib/zebra.h26
-rw-r--r--lib/zlog.c10
-rw-r--r--lib/zlog_targets.c60
35 files changed, 403 insertions, 189 deletions
diff --git a/lib/agentx.c b/lib/agentx.c
index b5a035ee2b..6d4e68d651 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -30,7 +30,7 @@
#include "smux.h"
#include "memory.h"
#include "linklist.h"
-#include "version.h"
+#include "lib/version.h"
#include "lib_errors.h"
#include "xref.h"
diff --git a/lib/bfd.c b/lib/bfd.c
index 276d6c685e..0974c26809 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -237,7 +237,7 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
memset(sp, 0, sizeof(*sp));
/* Get interface index. */
- ifindex = stream_getl(s);
+ STREAM_GETL(s, ifindex);
/* Lookup index. */
if (ifindex != 0) {
@@ -252,25 +252,28 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp,
}
/* Fetch destination address. */
- dp->family = stream_getc(s);
+ STREAM_GETC(s, dp->family);
plen = prefix_blen(dp);
- stream_get(&dp->u.prefix, s, plen);
- dp->prefixlen = stream_getc(s);
+ STREAM_GET(&dp->u.prefix, s, plen);
+ STREAM_GETC(s, dp->prefixlen);
/* Get BFD status. */
- *status = stream_getl(s);
+ STREAM_GETL(s, (*status));
- sp->family = stream_getc(s);
+ STREAM_GETC(s, sp->family);
plen = prefix_blen(sp);
- stream_get(&sp->u.prefix, s, plen);
- sp->prefixlen = stream_getc(s);
+ STREAM_GET(&sp->u.prefix, s, plen);
+ STREAM_GETC(s, sp->prefixlen);
- local_remote_cbit = stream_getc(s);
+ STREAM_GETC(s, local_remote_cbit);
if (remote_cbit)
*remote_cbit = local_remote_cbit;
return ifp;
+
+stream_failure:
+ return NULL;
}
/*
@@ -616,8 +619,6 @@ struct bfd_session_params {
/** BFD session installation state. */
bool installed;
- /** BFD session enabled. */
- bool enabled;
/** Global BFD paramaters list. */
TAILQ_ENTRY(bfd_session_params) entry;
@@ -745,6 +746,21 @@ static int _bfd_sess_send(struct thread *t)
bsp->installed = false;
else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER)
bsp->installed = true;
+ } else {
+ struct ipaddr src, dst;
+
+ src.ipa_type = bsp->args.family;
+ src.ipaddr_v6 = bsp->args.src;
+ dst.ipa_type = bsp->args.family;
+ dst.ipaddr_v6 = bsp->args.dst;
+
+ zlog_err(
+ "%s: BFD session %pIA -> %pIA interface %s VRF %s(%u) was not %s",
+ __func__, &src, &dst,
+ bsp->args.ifnamelen ? bsp->args.ifname : "*",
+ vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id,
+ bsp->lastev == BSE_INSTALL ? "installed"
+ : "uninstalled");
}
return 0;
@@ -779,18 +795,33 @@ void bfd_sess_free(struct bfd_session_params **bsp)
XFREE(MTYPE_BFD_INFO, (*bsp));
}
-void bfd_sess_enable(struct bfd_session_params *bsp, bool enable)
+static bool bfd_sess_address_changed(const struct bfd_session_params *bsp,
+ uint32_t family,
+ const struct in6_addr *src,
+ const struct in6_addr *dst)
{
- /* Remove the session when disabling. */
- if (!enable)
- _bfd_sess_remove(bsp);
+ size_t addrlen;
- bsp->enabled = enable;
+ if (bsp->args.family != family)
+ return true;
+
+ addrlen = (family == AF_INET) ? sizeof(struct in_addr)
+ : sizeof(struct in6_addr);
+ if ((src == NULL && memcmp(&bsp->args.src, &i6a_zero, addrlen))
+ || (src && memcmp(src, &bsp->args.src, addrlen))
+ || memcmp(dst, &bsp->args.dst, addrlen))
+ return true;
+
+ return false;
}
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
struct in_addr *src, struct in_addr *dst)
{
+ if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
+ (struct in6_addr *)dst))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
@@ -811,6 +842,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)
{
+ if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
+ (struct in6_addr *)dst))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
@@ -828,6 +863,10 @@ void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname)
{
+ if ((ifname == NULL && bsp->args.ifnamelen == 0)
+ || (ifname && strcmp(bsp->args.ifname, ifname) == 0))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
@@ -861,6 +900,9 @@ void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile)
void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
{
+ if (bsp->args.vrf_id == vrf_id)
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
@@ -871,6 +913,9 @@ 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);
@@ -882,6 +927,9 @@ void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl)
void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl)
{
+ if (bsp->args.ttl == min_ttl)
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
@@ -906,10 +954,6 @@ void bfd_sess_set_timers(struct bfd_session_params *bsp,
void bfd_sess_install(struct bfd_session_params *bsp)
{
- /* Don't attempt to install/update when disabled. */
- if (!bsp->enabled)
- return;
-
bsp->lastev = BSE_INSTALL;
thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
}
@@ -1057,8 +1101,8 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
/* Replay all activated peers. */
TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
- /* Skip disabled sessions. */
- if (!bsp->enabled)
+ /* Skip not installed sessions. */
+ if (!bsp->installed)
continue;
/* We are reconnecting, so we must send installation. */
@@ -1077,7 +1121,7 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
{
- struct bfd_session_params *bsp;
+ struct bfd_session_params *bsp, *bspn;
size_t sessions_updated = 0;
struct interface *ifp;
int remote_cbit = false;
@@ -1094,6 +1138,13 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit,
vrf_id);
+ /*
+ * When interface lookup fails or an invalid stream is read, we must
+ * not proceed otherwise it will trigger an assertion while checking
+ * family type below.
+ */
+ if (dp.family == 0 || sp.family == 0)
+ return 0;
if (bsglobal.debugging) {
ifstr[0] = 0;
@@ -1127,9 +1178,9 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
now = monotime(NULL);
/* Notify all matching sessions about update. */
- TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
- /* Skip disabled or not installed entries. */
- if (!bsp->enabled || !bsp->installed)
+ TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) {
+ /* Skip not installed entries. */
+ if (!bsp->installed)
continue;
/* Skip different VRFs. */
if (bsp->args.vrf_id != vrf_id)
diff --git a/lib/bfd.h b/lib/bfd.h
index 1325f86a30..113f167d3b 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -169,7 +169,7 @@ typedef void (*bsp_status_update)(struct bfd_session_params *bsp,
/**
* Allocates and initializes the session parameters.
*
- * \param updatedb status update notification callback.
+ * \param updatecb status update notification callback.
* \param args application independent data.
*
* \returns pointer to configuration storage.
@@ -185,16 +185,12 @@ struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args);
void bfd_sess_free(struct bfd_session_params **bsp);
/**
- * Enable/disable session installation.
- *
- * \param bsp session parameters.
- * \param enable knob variable.
- */
-void bfd_sess_enable(struct bfd_session_params *bsp, bool enable);
-
-/**
* Set the local and peer address of the BFD session.
*
+ * NOTE:
+ * If the address changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param src local address (optional, can be `NULL`).
* \param dst remote address (mandatory).
@@ -205,6 +201,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
/**
* Set the local and peer address of the BFD session.
*
+ * NOTE:
+ * If the address changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param src local address (optional, can be `NULL`).
* \param dst remote address (mandatory).
@@ -215,6 +215,10 @@ void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
/**
* Configure the BFD session interface.
*
+ * NOTE:
+ * If the interface changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param ifname interface name (or `NULL` to remove it).
*/
@@ -223,6 +227,9 @@ void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname);
/**
* Configure the BFD session profile name.
*
+ * NOTE:
+ * Session profile will only change after a `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param profile profile name (or `NULL` to remove it).
*/
@@ -231,6 +238,10 @@ void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile);
/**
* Configure the BFD session VRF.
*
+ * NOTE:
+ * If the VRF changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param vrf_id the VRF identification number.
*/
@@ -239,6 +250,10 @@ 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`.
+ *
* \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
@@ -260,6 +275,10 @@ void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_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).
@@ -269,6 +288,9 @@ void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl);
/**
* Configure the BFD session to set the Control Plane Independent bit.
*
+ * NOTE:
+ * Session CPI bit will only change after a `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param enable BFD Control Plane Independent state.
*/
@@ -280,6 +302,11 @@ void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable);
* Configures the BFD session timers to use. This is specially useful with
* `ptm-bfd` which does not support timers.
*
+ * NOTE:
+ * Session timers will only apply if the session has not been created yet.
+ * If the session is already installed you must uninstall and install again
+ * to take effect.
+ *
* \param bsp BFD session parameters.
* \param detection_multiplier the detection multiplier value.
* \param min_rx minimum required receive period.
@@ -292,6 +319,10 @@ void bfd_sess_set_timers(struct bfd_session_params *bsp,
/**
* Installs or updates the BFD session based on the saved session arguments.
*
+ * NOTE:
+ * This function has a delayed effect: it will only install/update after
+ * all northbound/CLI command batch finishes.
+ *
* \param bsp session parameters.
*/
void bfd_sess_install(struct bfd_session_params *bsp);
@@ -299,6 +330,10 @@ void bfd_sess_install(struct bfd_session_params *bsp);
/**
* Uninstall the BFD session based on the saved session arguments.
*
+ * NOTE:
+ * This function uninstalls the session immediately (if installed) and cancels
+ * any previous `bfd_sess_install` calls.
+ *
* \param bsp session parameters.
*/
void bfd_sess_uninstall(struct bfd_session_params *bsp);
diff --git a/lib/command.c b/lib/command.c
index d2798b5002..7fb405bdfb 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -900,13 +900,31 @@ enum node_type node_parent(enum node_type node)
/* Execute command by argument vline vector. */
static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
struct vty *vty,
- const struct cmd_element **cmd)
+ const struct cmd_element **cmd,
+ unsigned int up_level)
{
struct list *argv_list;
enum matcher_rv status;
const struct cmd_element *matched_element = NULL;
+ unsigned int i;
+ int xpath_index = vty->xpath_index;
+ int node = vty->node;
- struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
+ /* only happens for legacy split config file load; need to check for
+ * a match before calling node_exit handlers below
+ */
+ for (i = 0; i < up_level; i++) {
+ if (node <= CONFIG_NODE)
+ return CMD_NO_LEVEL_UP;
+
+ node = node_parent(node);
+
+ if (xpath_index > 0
+ && vty_check_node_for_xpath_decrement(node, vty->node))
+ xpath_index--;
+ }
+
+ struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
status = command_match(cmdgraph, vline, &argv_list, &matched_element);
if (cmd)
@@ -926,12 +944,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
}
}
+ for (i = 0; i < up_level; i++)
+ cmd_exit(vty);
+
// build argv array from argv list
struct cmd_token **argv = XMALLOC(
MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
struct listnode *ln;
struct cmd_token *token;
- unsigned int i = 0;
+
+ i = 0;
for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
argv[i++] = token;
@@ -1012,7 +1034,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
vector_lookup(vline, index));
ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
- vty, cmd);
+ vty, cmd, 0);
vector_free(shifted_vline);
vty->node = onode;
@@ -1021,7 +1043,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
}
saved_ret = ret =
- cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
+ cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
if (vtysh)
return saved_ret;
@@ -1038,7 +1060,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
onode))
vty->xpath_index--;
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
- vty, cmd);
+ vty, cmd, 0);
if (ret == CMD_SUCCESS || ret == CMD_WARNING
|| ret == CMD_NOT_MY_INSTANCE
|| ret == CMD_WARNING_CONFIG_FAILED)
@@ -1069,7 +1091,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
int cmd_execute_command_strict(vector vline, struct vty *vty,
const struct cmd_element **cmd)
{
- return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
+ return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
}
/*
@@ -1220,6 +1242,7 @@ int command_config_read_one_line(struct vty *vty,
{
vector vline;
int ret;
+ unsigned up_level = 0;
vline = cmd_make_strvec(vty->buf);
@@ -1230,36 +1253,20 @@ int command_config_read_one_line(struct vty *vty,
/* Execute configuration command : this is strict match */
ret = cmd_execute_command_strict(vline, vty, cmd);
- // Climb the tree and try the command again at each node
- if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
- && vty->node != CONFIG_NODE) {
- int saved_node = vty->node;
- int saved_xpath_index = vty->xpath_index;
-
- while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING
- && vty->node > CONFIG_NODE) {
- vty->node = node_parent(vty->node);
- if (vty->xpath_index > 0
- && vty_check_node_for_xpath_decrement(vty->node,
- saved_node))
- vty->xpath_index--;
- ret = cmd_execute_command_strict(vline, vty, cmd);
- }
-
- // If climbing the tree did not work then ignore the command and
- // stay at the same node
- if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING) {
- vty->node = saved_node;
- vty->xpath_index = saved_xpath_index;
- }
- }
+ /* The logic for trying parent nodes is in cmd_execute_command_real()
+ * since calling ->node_exit() correctly is a bit involved. This is
+ * also the only reason CMD_NO_LEVEL_UP exists.
+ */
+ while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
+ && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
+ && ret != CMD_SUCCESS && ret != CMD_WARNING
+ && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
+ && ret != CMD_NO_LEVEL_UP)
+ ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
+ ++up_level);
+
+ if (ret == CMD_NO_LEVEL_UP)
+ ret = CMD_ERR_NO_MATCH;
if (ret != CMD_SUCCESS &&
ret != CMD_WARNING &&
diff --git a/lib/command.h b/lib/command.h
index 14e51486ea..7e135dbcf6 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -223,6 +223,7 @@ struct cmd_node {
#define CMD_SUSPEND 12
#define CMD_WARNING_CONFIG_FAILED 13
#define CMD_NOT_MY_INSTANCE 14
+#define CMD_NO_LEVEL_UP 15
/* Argc max counts. */
#define CMD_ARGC_MAX 256
diff --git a/lib/command_lex.l b/lib/command_lex.l
index 0556605d63..9c096995f5 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -35,7 +35,7 @@
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-#include "command_parse.h"
+#include "lib/command_parse.h"
#define YY_USER_ACTION yylloc->last_column += yyleng;
#define LOC_STEP do { if (yylloc) { \
diff --git a/lib/command_parse.y b/lib/command_parse.y
index 5ebc19b278..f5e42cc304 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -75,7 +75,7 @@
%code provides {
#ifndef FLEX_SCANNER
- #include "command_lex.h"
+ #include "lib/command_lex.h"
#endif
extern void set_lexer_string (yyscan_t *scn, const char *string);
diff --git a/lib/defaults.c b/lib/defaults.c
index 7466aad5b1..fe099b6469 100644
--- a/lib/defaults.c
+++ b/lib/defaults.c
@@ -18,7 +18,7 @@
#include <zebra.h>
#include "defaults.h"
-#include "version.h"
+#include "lib/version.h"
static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first;
diff --git a/lib/filter.c b/lib/filter.c
index 5dbf30daa6..b7a935d076 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -175,6 +175,11 @@ void access_list_delete(struct access_list *access)
else
list->head = access->next;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
+
+ if (master->delete_hook)
+ master->delete_hook(access);
+
XFREE(MTYPE_ACCESS_LIST_STR, access->name);
XFREE(MTYPE_TMP, access->remark);
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index 08c29789b9..85805ffa47 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -508,17 +508,12 @@ static int lib_access_list_create(struct nb_cb_create_args *args)
static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
{
- struct access_master *am;
struct access_list *acl;
if (args->event != NB_EV_APPLY)
return NB_OK;
acl = nb_running_unset_entry(args->dnode);
- am = acl->master;
- if (am->delete_hook)
- am->delete_hook(acl);
-
access_list_delete(acl);
return NB_OK;
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 03359f4d18..898fe98aad 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -28,6 +28,7 @@
#include "memory.h"
#include "linklist.h"
#include "zlog.h"
+#include "libfrr.h"
#include "libfrr_trace.h"
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
@@ -162,6 +163,8 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
int ret;
sigset_t oldsigs, blocksigs;
+ assert(frr_is_after_fork || !"trying to start thread before fork()");
+
/* Ensure we never handle signals on a background thread by blocking
* everything here (new thread inherits signal mask)
*/
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
index 6e5088142a..17695e6607 100644
--- a/lib/lib_errors.c
+++ b/lib/lib_errors.c
@@ -45,9 +45,15 @@ static struct log_ref ferr_lib_warn[] = {
.suggestion = "Gather log data and open an Issue. restart FRR",
},
{
- .code = EC_LIB_SLOW_THREAD,
- .title = "The Event subsystem has detected a slow 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.",
+ .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",
+ .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",
.suggestion = "Gather log data and open an Issue",
},
{
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
index 4730b6aa33..9f0f58d20b 100644
--- a/lib/lib_errors.h
+++ b/lib/lib_errors.h
@@ -44,7 +44,8 @@ enum lib_log_refs {
EC_LIB_SNMP,
EC_LIB_STREAM,
EC_LIB_LINUX_NS,
- EC_LIB_SLOW_THREAD,
+ EC_LIB_SLOW_THREAD_CPU,
+ EC_LIB_SLOW_THREAD_WALL,
EC_LIB_NO_THREAD,
EC_LIB_RMAP_RECURSION_LIMIT,
EC_LIB_BACKUP_CONFIG,
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 5b0a523fb5..970e82c064 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -29,7 +29,7 @@
#include "privs.h"
#include "vty.h"
#include "command.h"
-#include "version.h"
+#include "lib/version.h"
#include "lib_vty.h"
#include "log_vty.h"
#include "zclient.h"
@@ -46,7 +46,8 @@
#include "frrscript.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
-DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_config_post, (struct thread_master * tm), (tm));
DEFINE_KOOH(frr_early_fini, (), ());
DEFINE_KOOH(frr_fini, (), ());
@@ -69,6 +70,8 @@ static char dbfile_default[512];
#endif
static char vtypath_default[512];
+/* cleared in frr_preinit(), then re-set after daemonizing */
+bool frr_is_after_fork = true;
bool debug_memstats_at_exit = false;
static bool nodetach_term, nodetach_daemon;
static uint64_t startup_fds;
@@ -307,6 +310,7 @@ void frr_init_vtydir(void)
void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
{
di = daemon;
+ frr_is_after_fork = false;
/* basename(), opencoded. */
char *p = strrchr(argv[0], '/');
@@ -931,6 +935,8 @@ static void frr_daemonize(void)
*/
static int frr_config_read_in(struct thread *t)
{
+ hook_call(frr_config_pre, master);
+
if (!vty_read_config(vty_shared_candidate_config, di->config_file,
config_default)
&& di->backup_config_file) {
@@ -964,7 +970,7 @@ static int frr_config_read_in(struct thread *t)
__func__, nb_err_name(ret), errmsg);
}
- hook_call(frr_very_late_init, master);
+ hook_call(frr_config_post, master);
return 0;
}
@@ -987,6 +993,8 @@ void frr_config_fork(void)
if (di->daemon_mode || di->terminal)
frr_daemonize();
+ frr_is_after_fork = true;
+
if (!di->pid_file)
di->pid_file = pidfile_default;
pid_output(di->pid_file);
diff --git a/lib/libfrr.h b/lib/libfrr.h
index db0f364986..3dc5d7af81 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -141,8 +141,12 @@ extern enum frr_cli_mode frr_get_cli_mode(void);
extern uint32_t frr_get_fd_limit(void);
extern bool frr_is_startup_fd(int fd);
+/* call order of these hooks is as ordered here */
DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
-DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+/* fork() happens between late_init and config_pre */
+DECLARE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
+DECLARE_HOOK(frr_config_post, (struct thread_master * tm), (tm));
+
extern void frr_config_fork(void);
extern void frr_run(struct thread_master *master);
@@ -168,6 +172,8 @@ extern const char frr_scriptdir[];
extern char frr_protoname[];
extern char frr_protonameinst[];
+/* always set in the spot where we *would* fork even if we don't do so */
+extern bool frr_is_after_fork;
extern bool debug_memstats_at_exit;
diff --git a/lib/log_vty.c b/lib/log_vty.c
index c26621ae99..c6788dd35a 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -146,11 +146,11 @@ void log_show_syslog(struct vty *vty)
zlog_progname);
}
-DEFUN (show_logging,
- show_logging_cmd,
- "show logging",
- SHOW_STR
- "Show current logging configuration\n")
+DEFUN_NOSH (show_logging,
+ show_logging_cmd,
+ "show logging",
+ SHOW_STR
+ "Show current logging configuration\n")
{
log_show_syslog(vty);
diff --git a/lib/module.c b/lib/module.c
index d2491a3479..1d51a6396d 100644
--- a/lib/module.c
+++ b/lib/module.c
@@ -25,7 +25,7 @@
#include "module.h"
#include "memory.h"
-#include "version.h"
+#include "lib/version.h"
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index f88c2161da..81e30bce49 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -20,7 +20,7 @@
#include <zebra.h>
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "defaults.h"
#include "log.h"
#include "lib_errors.h"
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index 3d8771ffbc..403537e043 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -24,7 +24,7 @@
#include "command.h"
#include "debug.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include <confd_lib.h>
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index d042e15dad..58f4e42516 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -23,7 +23,7 @@
#include "log.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "command.h"
#include "lib_errors.h"
#include "northbound.h"
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 9fc640ceea..63fd40f8d3 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -25,7 +25,7 @@
#include "debug.h"
#include "memory.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include <sysrepo.h>
@@ -736,7 +736,7 @@ static int frr_sr_finish(void)
return 0;
}
-static int frr_sr_module_very_late_init(struct thread_master *tm)
+static int frr_sr_module_config_loaded(struct thread_master *tm)
{
master = tm;
@@ -761,7 +761,7 @@ static int frr_sr_module_late_init(struct thread_master *tm)
static int frr_sr_module_init(void)
{
hook_register(frr_late_init, frr_sr_module_late_init);
- hook_register(frr_very_late_init, frr_sr_module_very_late_init);
+ hook_register(frr_config_post, frr_sr_module_config_loaded);
return 0;
}
diff --git a/lib/pid_output.c b/lib/pid_output.c
index bd1d89a94c..b82dde8258 100644
--- a/lib/pid_output.c
+++ b/lib/pid_output.c
@@ -22,7 +22,7 @@
#include <zebra.h>
#include <fcntl.h>
#include <log.h>
-#include "version.h"
+#include "lib/version.h"
#include "network.h"
#include "lib_errors.h"
diff --git a/lib/sha256.c b/lib/sha256.c
index 37ced5b402..a9b7a4aefc 100644
--- a/lib/sha256.c
+++ b/lib/sha256.c
@@ -35,8 +35,6 @@ static inline uint32_t be32dec(const void *pp)
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8)
+ ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
-#else
-#include <sys/endian.h>
#endif
#if !HAVE_DECL_BE32ENC
@@ -49,8 +47,6 @@ static inline void be32enc(void *pp, uint32_t x)
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
-#else
-#include <sys/endian.h>
#endif
/*
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 64cec1385d..be7297f264 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -237,9 +237,12 @@ core_handler(int signo, siginfo_t *siginfo, void *context)
/* make sure we don't hang in here. default for SIGALRM is terminate.
* - if we're in backtrace for more than a second, abort. */
struct sigaction sa_default = {.sa_handler = SIG_DFL};
+
sigaction(SIGALRM, &sa_default, NULL);
+ sigaction(signo, &sa_default, NULL);
sigset_t sigset;
+
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
@@ -252,7 +255,16 @@ core_handler(int signo, siginfo_t *siginfo, void *context)
log_memstats(stderr, "core_handler");
zlog_tls_buffer_fini();
- abort();
+
+ /* give the kernel a chance to generate a coredump */
+ sigaddset(&sigset, signo);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+ raise(signo);
+
+ /* only chance to end up here is if the default action for signo is
+ * something other than kill or coredump the process
+ */
+ _exit(128 + signo);
}
static void trap_default_signals(void)
diff --git a/lib/sockopt.c b/lib/sockopt.c
index ed21b72df7..b624fe2230 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -25,6 +25,16 @@
#include "sockunion.h"
#include "lib_errors.h"
+#if (defined(__FreeBSD__) \
+ && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) \
+ || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) \
+ || (defined(__NetBSD__) && defined(__NetBSD_Version__) \
+ && __NetBSD_Version__ >= 106010000) \
+ || defined(__OpenBSD__) || defined(__APPLE__) \
+ || defined(__DragonFly__) || defined(__sun)
+#define HAVE_BSD_STRUCT_IP_MREQ_HACK
+#endif
+
void setsockopt_so_recvbuf(int sock, int size)
{
int orig_req = size;
diff --git a/lib/subdir.am b/lib/subdir.am
index 0853d4bb2b..98ba1cf24c 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -141,10 +141,14 @@ vtysh_scan += \
lib/if_rmap.c \
lib/keychain.c \
lib/lib_vty.c \
+ lib/log_vty.c \
lib/nexthop_group.c \
lib/plist.c \
+ lib/resolver.c \
lib/routemap.c \
lib/routemap_cli.c \
+ lib/spf_backoff.c \
+ lib/thread.c \
lib/vrf.c \
lib/vty.c \
# end
@@ -314,7 +318,7 @@ if SNMP
lib_LTLIBRARIES += lib/libfrrsnmp.la
endif
-lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+lib_libfrrsnmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS)
lib_libfrrsnmp_la_SOURCES = \
@@ -330,7 +334,7 @@ lib_LTLIBRARIES += lib/libfrrcares.la
pkginclude_HEADERS += lib/resolver.h
endif
-lib_libfrrcares_la_CFLAGS = $(WERROR) $(CARES_CFLAGS)
+lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS)
lib_libfrrcares_la_LDFLAGS = -version-info 0:0:0
lib_libfrrcares_la_LIBADD = $(CARES_LIBS)
lib_libfrrcares_la_SOURCES = \
@@ -345,7 +349,7 @@ lib_LTLIBRARIES += lib/libfrrzmq.la
pkginclude_HEADERS += lib/frr_zmq.h
endif
-lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS)
+lib_libfrrzmq_la_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0
lib_libfrrzmq_la_LIBADD = $(ZEROMQ_LIBS)
lib_libfrrzmq_la_SOURCES = \
@@ -359,7 +363,7 @@ if CONFD
module_LTLIBRARIES += lib/confd.la
endif
-lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS)
+lib_confd_la_CFLAGS = $(AM_CFLAGS) $(CONFD_CFLAGS)
lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS)
lib_confd_la_SOURCES = lib/northbound_confd.c
@@ -371,7 +375,7 @@ if SYSREPO
module_LTLIBRARIES += lib/sysrepo.la
endif
-lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS)
+lib_sysrepo_la_CFLAGS = $(AM_CFLAGS) $(SYSREPO_CFLAGS)
lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS)
lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c
@@ -410,7 +414,7 @@ lib_grammar_sandbox_LDADD = \
lib/libfrr.la
lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY
-lib_clippy_CFLAGS = $(PYTHON_CFLAGS)
+lib_clippy_CFLAGS = $(AC_CFLAGS) $(PYTHON_CFLAGS)
lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) -lelf
lib_clippy_LDFLAGS = -export-dynamic
lib_clippy_SOURCES = \
diff --git a/lib/thread.c b/lib/thread.c
index 866090341e..3d8b544678 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -124,11 +124,12 @@ static void cpu_record_hash_free(void *a)
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
- vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
+ vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu",
a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
- a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
- (a->real.total / a->total_calls), a->real.max);
- vty_out(vty, " %c%c%c%c%c %s\n",
+ a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
+ (a->real.total / a->total_calls), a->real.max,
+ a->total_cpu_warn, a->total_wall_warn);
+ vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
@@ -149,6 +150,10 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[])
atomic_load_explicit(&a->total_active, memory_order_seq_cst);
copy.total_calls =
atomic_load_explicit(&a->total_calls, memory_order_seq_cst);
+ copy.total_cpu_warn =
+ atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst);
+ copy.total_wall_warn =
+ atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst);
copy.cpu.total =
atomic_load_explicit(&a->cpu.total, memory_order_seq_cst);
copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst);
@@ -165,6 +170,8 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[])
vty_out_cpu_thread_history(vty, &copy);
totals->total_active += copy.total_active;
totals->total_calls += copy.total_calls;
+ totals->total_cpu_warn += copy.total_cpu_warn;
+ totals->total_wall_warn += copy.total_wall_warn;
totals->real.total += copy.real.total;
if (totals->real.max < copy.real.max)
totals->real.max = copy.real.max;
@@ -202,7 +209,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
vty_out(vty,
"Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
- vty_out(vty, " Type Thread\n");
+ vty_out(vty, " CPU_Warn Wall_Warn Type Thread\n");
if (m->cpu_record->count)
hash_iterate(
@@ -223,7 +230,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
vty_out(vty, "%30s %18s %18s\n", "",
"CPU (user+system):", "Real (wall-clock):");
vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
- vty_out(vty, " Avg uSec Max uSecs");
+ vty_out(vty, " Avg uSec Max uSecs CPU_Warn Wall_Warn");
vty_out(vty, " Type Thread\n");
if (tmp.total_calls > 0)
@@ -300,13 +307,13 @@ static uint8_t parse_filter(const char *filterstr)
}
#ifndef EXCLUDE_CPU_TIME
-DEFUN (show_thread_cpu,
- show_thread_cpu_cmd,
- "show thread cpu [FILTER]",
- SHOW_STR
- "Thread information\n"
- "Thread CPU usage\n"
- "Display filter (rwtex)\n")
+DEFUN_NOSH (show_thread_cpu,
+ show_thread_cpu_cmd,
+ "show thread cpu [FILTER]",
+ SHOW_STR
+ "Thread information\n"
+ "Thread CPU usage\n"
+ "Display filter (rwtex)\n")
{
uint8_t filter = (uint8_t)-1U;
int idx = 0;
@@ -367,12 +374,12 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
}
}
-DEFUN (show_thread_poll,
- show_thread_poll_cmd,
- "show thread poll",
- SHOW_STR
- "Thread information\n"
- "Show poll FD's and information\n")
+DEFUN_NOSH (show_thread_poll,
+ show_thread_poll_cmd,
+ "show thread poll",
+ SHOW_STR
+ "Thread information\n"
+ "Show poll FD's and information\n")
{
struct listnode *node;
struct thread_master *m;
@@ -1850,15 +1857,33 @@ void thread_call(struct thread *thread)
memory_order_seq_cst);
#ifdef CONSUMED_TIME_CHECK
- if (realtime > CONSUMED_TIME_CHECK) {
+ if (cputime > CONSUMED_TIME_CHECK) {
/*
- * We have a CPU Hog on our hands.
+ * We have a CPU Hog on our hands. The time FRR
+ * has spent doing actual work ( not sleeping )
+ * is greater than 5 seconds.
* Whinge about it now, so we're aware this is yet another task
* to fix.
*/
+ atomic_fetch_add_explicit(&thread->hist->total_cpu_warn,
+ 1, memory_order_seq_cst);
+ flog_warn(
+ EC_LIB_SLOW_THREAD_CPU,
+ "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)",
+ thread->xref->funcname, (unsigned long)thread->func,
+ realtime / 1000, cputime / 1000);
+ } else if (realtime > CONSUMED_TIME_CHECK) {
+ /*
+ * The runtime for a task is greater than 5 seconds, but
+ * the cpu time is under 5 seconds. Let's whine
+ * about this because this could imply some sort of
+ * scheduling issue.
+ */
+ atomic_fetch_add_explicit(&thread->hist->total_wall_warn,
+ 1, memory_order_seq_cst);
flog_warn(
- EC_LIB_SLOW_THREAD,
- "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
+ EC_LIB_SLOW_THREAD_WALL,
+ "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)",
thread->xref->funcname, (unsigned long)thread->func,
realtime / 1000, cputime / 1000);
}
diff --git a/lib/thread.h b/lib/thread.h
index af68331131..fee728dbf9 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -119,6 +119,8 @@ struct thread {
struct cpu_thread_history {
int (*func)(struct thread *);
+ atomic_size_t total_cpu_warn;
+ atomic_size_t total_wall_warn;
atomic_size_t total_calls;
atomic_size_t total_active;
struct time_stats {
diff --git a/lib/version.h.in b/lib/version.h.in
index d535d131c8..5078f3ad6e 100644
--- a/lib/version.h.in
+++ b/lib/version.h.in
@@ -25,7 +25,7 @@
#define _ZEBRA_VERSION_H
#ifdef GIT_VERSION
-#include "gitversion.h"
+#include "lib/gitversion.h"
#endif
#ifdef __cplusplus
diff --git a/lib/vty.c b/lib/vty.c
index 96cfef1c0a..f92c912084 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -515,13 +515,19 @@ static int vty_command(struct vty *vty, char *buf)
#ifdef CONSUMED_TIME_CHECK
GETRUSAGE(&after);
- if ((realtime = thread_consumed_time(&after, &before, &cputime))
- > CONSUMED_TIME_CHECK)
+ realtime = thread_consumed_time(&after, &before, &cputime);
+ if (cputime > CONSUMED_TIME_CHECK) {
/* Warn about CPU hog that must be fixed. */
flog_warn(
- EC_LIB_SLOW_THREAD,
- "SLOW COMMAND: command took %lums (cpu time %lums): %s",
+ EC_LIB_SLOW_THREAD_CPU,
+ "CPU HOG: command took %lums (cpu time %lums): %s",
realtime / 1000, cputime / 1000, buf);
+ } else if (realtime > CONSUMED_TIME_CHECK) {
+ flog_warn(
+ EC_LIB_SLOW_THREAD_WALL,
+ "STARVATION: command took %lums (cpu time %lums): %s",
+ realtime / 1000, cputime / 1000, buf);
+ }
}
#endif /* CONSUMED_TIME_CHECK */
diff --git a/lib/xref.h b/lib/xref.h
index b1cb172b41..63166b069a 100644
--- a/lib/xref.h
+++ b/lib/xref.h
@@ -137,6 +137,19 @@ extern void xref_gcc_workaround(const struct xref *xref);
extern const struct xref * const __start_xref_array[1] DSO_LOCAL;
extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+/* no redzone around each of the xref_p please, we're building an array out
+ * of variables here. kinda breaks things if there's redzones between each
+ * array item.
+ */
+#define xref_array_attr used, section("xref_array"), no_sanitize("address")
+#endif
+#endif
+#ifndef xref_array_attr
+#define xref_array_attr used, section("xref_array")
+#endif
+
/* this macro is invoked once for each standalone DSO through
* FRR_MODULE_SETUP \
* }-> FRR_COREMOD_SETUP -> XREF_SETUP
@@ -151,8 +164,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
/* .func = */ "dummy", \
}; \
static const struct xref * const _dummy_xref_p \
- __attribute__((used, section("xref_array"))) \
- = &_dummy_xref; \
+ __attribute__((xref_array_attr)) = &_dummy_xref; \
static void __attribute__((used, _CONSTRUCTOR(1100))) \
_xref_init(void) { \
static struct xref_block _xref_block = { \
@@ -225,7 +237,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
#if defined(__clang__) || !defined(__cplusplus)
#define XREF_LINK(dst) \
static const struct xref * const NAMECTR(xref_p_) \
- __attribute__((used, section("xref_array"))) \
+ __attribute__((xref_array_attr)) \
= &(dst) \
/* end */
diff --git a/lib/zclient.h b/lib/zclient.h
index 90240e40b2..26fa73fc0a 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -754,6 +754,29 @@ enum zclient_send_status {
};
static inline const char *
+zapi_nhg_notify_owner2str(enum zapi_nhg_notify_owner note)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (note) {
+ case ZAPI_NHG_FAIL_INSTALL:
+ ret = "ZAPI_NHG_FAIL_INSTALL";
+ break;
+ case ZAPI_NHG_INSTALLED:
+ ret = "ZAPI_NHG_INSTALLED";
+ break;
+ case ZAPI_NHG_REMOVE_FAIL:
+ ret = "ZAPI_NHG_REMOVE_FAIL";
+ break;
+ case ZAPI_NHG_REMOVED:
+ ret = "ZAPI_NHG_REMOVED";
+ break;
+ }
+
+ return ret;
+}
+
+static inline const char *
zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
{
const char *ret = "UNKNOWN";
diff --git a/lib/zebra.h b/lib/zebra.h
index 5c3d91ba74..26c0fe05b5 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -68,6 +68,12 @@
#include <limits.h>
#include <inttypes.h>
#include <stdbool.h>
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#endif
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
/* machine dependent includes */
#ifdef HAVE_LINUX_VERSION_H
@@ -280,22 +286,10 @@ struct in_pktinfo {
#define HAVE_IP_HDRINCL_BSD_ORDER
#endif
-/* Define BYTE_ORDER, if not defined. Useful for compiler conditional
- * code, rather than preprocessor conditional.
- * Not all the world has this BSD define.
- */
+/* autoconf macros for this are deprecated, just find endian.h */
#ifndef BYTE_ORDER
-#define BIG_ENDIAN 4321 /* least-significant byte first (vax, pc) */
-#define LITTLE_ENDIAN 1234 /* most-significant byte first (IBM, net) */
-#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */
-
-#if defined(WORDS_BIGENDIAN)
-#define BYTE_ORDER BIG_ENDIAN
-#else /* !WORDS_BIGENDIAN */
-#define BYTE_ORDER LITTLE_ENDIAN
-#endif /* WORDS_BIGENDIAN */
-
-#endif /* ndef BYTE_ORDER */
+#error please locate an endian.h file appropriate to your platform
+#endif
/* For old definition. */
#ifndef IN6_ARE_ADDR_EQUAL
@@ -312,7 +306,7 @@ struct in_pktinfo {
#include "compiler.h"
/* Zebra route's types are defined in route_types.h */
-#include "route_types.h"
+#include "lib/route_types.h"
#define strmatch(a,b) (!strcmp((a), (b)))
diff --git a/lib/zlog.c b/lib/zlog.c
index f546709328..24800c6e64 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -142,6 +142,7 @@ struct zlog_msg {
struct zlog_tls {
char *mmbuf;
size_t bufpos;
+ bool do_unlink;
size_t nmsgs;
struct zlog_msg msgs[TLS_LOG_MAXMSG];
@@ -266,13 +267,14 @@ void zlog_tls_buffer_init(void)
mmpath, strerror(errno));
goto out_anon_unlink;
}
+ zlog_tls->do_unlink = true;
close(mmfd);
zlog_tls_set(zlog_tls);
return;
out_anon_unlink:
- unlink(mmpath);
+ unlinkat(zlog_tmpdirfd, mmpath, 0);
close(mmfd);
out_anon:
@@ -296,14 +298,16 @@ out_anon:
void zlog_tls_buffer_fini(void)
{
char mmpath[MAXPATHLEN];
+ struct zlog_tls *zlog_tls = zlog_tls_get();
+ bool do_unlink = zlog_tls ? zlog_tls->do_unlink : false;
zlog_tls_buffer_flush();
- zlog_tls_free(zlog_tls_get());
+ zlog_tls_free(zlog_tls);
zlog_tls_set(NULL);
snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
- if (unlinkat(zlog_tmpdirfd, mmpath, 0))
+ if (do_unlink && unlinkat(zlog_tmpdirfd, mmpath, 0))
zlog_err("unlink logbuf: %s (%d)", strerror(errno), errno);
}
diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c
index f258a8fbbd..7799fbfda7 100644
--- a/lib/zlog_targets.c
+++ b/lib/zlog_targets.c
@@ -78,40 +78,48 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
struct zlog_msg *msg = msgs[i];
int prio = zlog_msg_prio(msg);
- if (prio > zt->prio_min)
- continue;
-
- iov[iovpos].iov_base = ts_pos;
- if (iovpos > 0)
- *ts_pos++ = '\n';
- ts_pos += zlog_msg_ts(msg, ts_pos, sizeof(ts_buf) - 1
- - (ts_pos - ts_buf),
- ZLOG_TS_LEGACY | zte->ts_subsec);
- *ts_pos++ = ' ';
- iov[iovpos].iov_len = ts_pos - (char *)iov[iovpos].iov_base;
+ if (prio <= zt->prio_min) {
+ iov[iovpos].iov_base = ts_pos;
+ if (iovpos > 0)
+ *ts_pos++ = '\n';
+ ts_pos += zlog_msg_ts(msg, ts_pos,
+ sizeof(ts_buf) - 1
+ - (ts_pos - ts_buf),
+ ZLOG_TS_LEGACY | zte->ts_subsec);
+ *ts_pos++ = ' ';
+ iov[iovpos].iov_len =
+ ts_pos - (char *)iov[iovpos].iov_base;
- iovpos++;
+ iovpos++;
- if (zte->record_priority) {
- iov[iovpos].iov_base = (char *)prionames[prio];
- iov[iovpos].iov_len = strlen(iov[iovpos].iov_base);
+ if (zte->record_priority) {
+ iov[iovpos].iov_base = (char *)prionames[prio];
+ iov[iovpos].iov_len =
+ strlen(iov[iovpos].iov_base);
- iovpos++;
- }
+ iovpos++;
+ }
- iov[iovpos].iov_base = zlog_prefix;
- iov[iovpos].iov_len = zlog_prefixsz;
+ iov[iovpos].iov_base = zlog_prefix;
+ iov[iovpos].iov_len = zlog_prefixsz;
- iovpos++;
+ iovpos++;
- iov[iovpos].iov_base = (char *)zlog_msg_text(msg, &textlen);
- iov[iovpos].iov_len = textlen;
+ iov[iovpos].iov_base =
+ (char *)zlog_msg_text(msg, &textlen);
+ iov[iovpos].iov_len = textlen;
- iovpos++;
+ iovpos++;
+ }
- if (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
- || i + 1 == nmsgs
- || array_size(iov) - iovpos < 5) {
+ /* conditions that trigger writing:
+ * - out of space for more timestamps/headers
+ * - this being the last message in the batch
+ * - not enough remaining iov entries
+ */
+ if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
+ || i + 1 == nmsgs
+ || array_size(iov) - iovpos < 5)) {
iov[iovpos].iov_base = (char *)"\n";
iov[iovpos].iov_len = 1;