diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/agentx.c | 2 | ||||
| -rw-r--r-- | lib/bfd.c | 103 | ||||
| -rw-r--r-- | lib/bfd.h | 53 | ||||
| -rw-r--r-- | lib/command.c | 81 | ||||
| -rw-r--r-- | lib/command.h | 1 | ||||
| -rw-r--r-- | lib/command_lex.l | 2 | ||||
| -rw-r--r-- | lib/command_parse.y | 2 | ||||
| -rw-r--r-- | lib/defaults.c | 2 | ||||
| -rw-r--r-- | lib/filter.c | 5 | ||||
| -rw-r--r-- | lib/filter_nb.c | 5 | ||||
| -rw-r--r-- | lib/frr_pthread.c | 3 | ||||
| -rw-r--r-- | lib/lib_errors.c | 12 | ||||
| -rw-r--r-- | lib/lib_errors.h | 3 | ||||
| -rw-r--r-- | lib/libfrr.c | 14 | ||||
| -rw-r--r-- | lib/libfrr.h | 8 | ||||
| -rw-r--r-- | lib/log_vty.c | 10 | ||||
| -rw-r--r-- | lib/module.c | 2 | ||||
| -rw-r--r-- | lib/northbound_cli.c | 2 | ||||
| -rw-r--r-- | lib/northbound_confd.c | 2 | ||||
| -rw-r--r-- | lib/northbound_grpc.cpp | 2 | ||||
| -rw-r--r-- | lib/northbound_sysrepo.c | 6 | ||||
| -rw-r--r-- | lib/pid_output.c | 2 | ||||
| -rw-r--r-- | lib/sha256.c | 4 | ||||
| -rw-r--r-- | lib/sigevent.c | 14 | ||||
| -rw-r--r-- | lib/sockopt.c | 10 | ||||
| -rw-r--r-- | lib/subdir.am | 16 | ||||
| -rw-r--r-- | lib/thread.c | 71 | ||||
| -rw-r--r-- | lib/thread.h | 2 | ||||
| -rw-r--r-- | lib/version.h.in | 2 | ||||
| -rw-r--r-- | lib/vty.c | 14 | ||||
| -rw-r--r-- | lib/xref.h | 18 | ||||
| -rw-r--r-- | lib/zclient.h | 23 | ||||
| -rw-r--r-- | lib/zebra.h | 26 | ||||
| -rw-r--r-- | lib/zlog.c | 10 | ||||
| -rw-r--r-- | lib/zlog_targets.c | 60 |
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" @@ -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) @@ -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, ©); 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 @@ -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; |
