summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/atomlist.c2
-rw-r--r--lib/elf_py.c3
-rw-r--r--lib/filter.c58
-rw-r--r--lib/filter_cli.c14
-rw-r--r--lib/frrcu.h2
-rw-r--r--lib/log_vty.c61
-rw-r--r--lib/resolver.c178
-rw-r--r--lib/routemap_cli.c12
-rw-r--r--lib/typerb.h1
-rw-r--r--lib/typesafe.c1
-rw-r--r--lib/typesafe.h1
-rw-r--r--lib/vector.c11
-rw-r--r--lib/vector.h1
-rw-r--r--lib/xref.c4
-rw-r--r--lib/xref.h13
-rw-r--r--lib/zlog.c97
-rw-r--r--lib/zlog.h22
17 files changed, 377 insertions, 104 deletions
diff --git a/lib/atomlist.c b/lib/atomlist.c
index 3668b083d0..b7c9516a00 100644
--- a/lib/atomlist.c
+++ b/lib/atomlist.c
@@ -18,6 +18,8 @@
#include "config.h"
#endif
+#include <assert.h>
+
#include "atomlist.h"
void atomlist_add_head(struct atomlist_head *h, struct atomlist_item *item)
diff --git a/lib/elf_py.c b/lib/elf_py.c
index 1c306893ad..f230add695 100644
--- a/lib/elf_py.c
+++ b/lib/elf_py.c
@@ -636,6 +636,9 @@ static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx)
Elf_Scn *scn = elf_getscn(ef->elf, i);
GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr);
+ /* virtual address is kinda meaningless for TLS sections */
+ if (shdr->sh_flags & SHF_TLS)
+ continue;
if (addr < shdr->sh_addr ||
addr >= shdr->sh_addr + shdr->sh_size)
continue;
diff --git a/lib/filter.c b/lib/filter.c
index 3a86fbce93..9c80808fe8 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -612,7 +612,7 @@ DEFUN (show_mac_access_list,
DEFUN (show_mac_access_list_name,
show_mac_access_list_name_cmd,
- "show mac access-list WORD",
+ "show mac access-list ACCESSLIST_MAC_NAME",
SHOW_STR
"mac access lists\n"
"List mac access lists\n"
@@ -635,7 +635,7 @@ DEFUN (show_ip_access_list,
DEFUN (show_ip_access_list_name,
show_ip_access_list_name_cmd,
- "show ip access-list WORD [json]",
+ "show ip access-list ACCESSLIST4_NAME [json]",
SHOW_STR
IP_STR
"List IP access lists\n"
@@ -661,7 +661,7 @@ DEFUN (show_ipv6_access_list,
DEFUN (show_ipv6_access_list_name,
show_ipv6_access_list_name_cmd,
- "show ipv6 access-list WORD [json]",
+ "show ipv6 access-list ACCESSLIST6_NAME [json]",
SHOW_STR
IPV6_STR
"List IPv6 access lists\n"
@@ -839,12 +839,62 @@ static void access_list_init_ipv4(void)
install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
}
+static void access_list_autocomplete_afi(afi_t afi, vector comps,
+ struct cmd_token *token)
+{
+ struct access_list *access;
+ struct access_list *next;
+ struct access_master *master;
+
+ master = access_master_get(afi);
+ if (master == NULL)
+ return;
+
+ for (access = master->str.head; access; access = next) {
+ next = access->next;
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, access->name));
+ }
+}
+
static struct cmd_node access_ipv6_node = {
.name = "ipv6 access list",
.node = ACCESS_IPV6_NODE,
.prompt = "",
};
+static void access_list_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP, comps, token);
+ access_list_autocomplete_afi(AFI_IP6, comps, token);
+ access_list_autocomplete_afi(AFI_L2VPN, comps, token);
+}
+
+static void access_list4_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP, comps, token);
+}
+
+static void access_list6_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_IP6, comps, token);
+}
+
+static void access_list_mac_autocomplete(vector comps, struct cmd_token *token)
+{
+ access_list_autocomplete_afi(AFI_L2VPN, comps, token);
+}
+
+static const struct cmd_variable_handler access_list_handlers[] = {
+ {.tokenname = "ACCESSLIST_NAME",
+ .completions = access_list_autocomplete},
+ {.tokenname = "ACCESSLIST4_NAME",
+ .completions = access_list4_autocomplete},
+ {.tokenname = "ACCESSLIST6_NAME",
+ .completions = access_list6_autocomplete},
+ {.tokenname = "ACCESSLIST_MAC_NAME",
+ .completions = access_list_mac_autocomplete},
+ {.completions = NULL}};
+
static void access_list_reset_ipv6(void)
{
struct access_list *access;
@@ -874,6 +924,8 @@ static void access_list_init_ipv6(void)
void access_list_init(void)
{
+ cmd_variable_handler_register(access_list_handlers);
+
access_list_init_ipv4();
access_list_init_ipv6();
access_list_init_mac();
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 43618094ac..fb40c527dd 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -822,7 +822,7 @@ DEFPY_YANG(
ALIAS(
no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd,
- "no ipv6 access-list WORD$name remark LINE...",
+ "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...",
NO_STR
IPV6_STR
ACCESS_LIST_STR
@@ -832,7 +832,7 @@ ALIAS(
DEFPY_YANG(
mac_access_list, mac_access_list_cmd,
- "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
+ "mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
MAC_STR
ACCESS_LIST_STR
ACCESS_LIST_ZEBRA_STR
@@ -898,7 +898,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_mac_access_list, no_mac_access_list_cmd,
- "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
+ "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -938,7 +938,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_mac_access_list_all, no_mac_access_list_all_cmd,
- "no mac access-list WORD$name",
+ "no mac access-list ACCESSLIST_MAC_NAME$name",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -955,7 +955,7 @@ DEFPY_YANG(
DEFPY_YANG(
mac_access_list_remark, mac_access_list_remark_cmd,
- "mac access-list WORD$name remark LINE...",
+ "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
MAC_STR
ACCESS_LIST_STR
ACCESS_LIST_ZEBRA_STR
@@ -980,7 +980,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_mac_access_list_remark, no_mac_access_list_remark_cmd,
- "no mac access-list WORD$name remark",
+ "no mac access-list ACCESSLIST_MAC_NAME$name remark",
NO_STR
MAC_STR
ACCESS_LIST_STR
@@ -1004,7 +1004,7 @@ DEFPY_YANG(
ALIAS(
no_mac_access_list_remark, no_mac_access_list_remark_line_cmd,
- "no mac access-list WORD$name remark LINE...",
+ "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
NO_STR
MAC_STR
ACCESS_LIST_STR
diff --git a/lib/frrcu.h b/lib/frrcu.h
index 3808259040..ae840926b5 100644
--- a/lib/frrcu.h
+++ b/lib/frrcu.h
@@ -17,6 +17,8 @@
#ifndef _FRRCU_H
#define _FRRCU_H
+#include <assert.h>
+
#include "memory.h"
#include "atomlist.h"
diff --git a/lib/log_vty.c b/lib/log_vty.c
index cbb8de8976..9911323553 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -36,6 +36,8 @@
DEFINE_HOOK(zlog_rotate, (), ());
DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
+static unsigned logmsgs_with_persist_bt;
+
static const int log_default_lvl = LOG_DEBUG;
static int log_config_stdout_lvl = ZLOG_DISABLED;
@@ -267,6 +269,44 @@ DEFUN_HIDDEN (no_config_log_monitor,
return CMD_SUCCESS;
}
+DEFPY (debug_uid_backtrace,
+ debug_uid_backtrace_cmd,
+ "[no] debug unique-id UID backtrace",
+ NO_STR
+ DEBUG_STR
+ "Options per individual log message, by unique ID\n"
+ "Log message unique ID (XXXXX-XXXXX)\n"
+ "Add backtrace to log when message is printed\n")
+{
+ struct xrefdata search, *xrd;
+ struct xrefdata_logmsg *xrdl;
+ uint8_t flag;
+
+ strlcpy(search.uid, uid, sizeof(search.uid));
+ xrd = xrefdata_uid_find(&xrefdata_uid, &search);
+
+ if (!xrd) {
+ vty_out(vty, "%% no log message with ID \"%s\" found\n", uid);
+ return CMD_WARNING;
+ }
+ if (xrd->xref->type != XREFT_LOGMSG) {
+ vty_out(vty, "%% ID \"%s\" is not a log message\n", uid);
+ return CMD_WARNING;
+ }
+ xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata);
+
+ flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT
+ : LOGMSG_FLAG_EPHEMERAL;
+
+ if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag))
+ return CMD_SUCCESS;
+ if (flag == LOGMSG_FLAG_PERSISTENT)
+ logmsgs_with_persist_bt += no ? -1 : 1;
+
+ xrdl->fl_print_bt ^= flag;
+ return CMD_SUCCESS;
+}
+
static int set_log_file(struct zlog_cfg_file *target, struct vty *vty,
const char *fname, int loglevel)
{
@@ -751,6 +791,24 @@ void log_config_write(struct vty *vty)
vty_out(vty, "no log error-category\n");
if (!zlog_get_prefix_xid())
vty_out(vty, "no log unique-id\n");
+
+ if (logmsgs_with_persist_bt) {
+ struct xrefdata *xrd;
+ struct xrefdata_logmsg *xrdl;
+
+ vty_out(vty, "!\n");
+
+ frr_each (xrefdata_uid, &xrefdata_uid, xrd) {
+ if (xrd->xref->type != XREFT_LOGMSG)
+ continue;
+
+ xrdl = container_of(xrd, struct xrefdata_logmsg,
+ xrefdata);
+ if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT)
+ vty_out(vty, "debug unique-id %s backtrace\n",
+ xrd->uid);
+ }
+ }
}
static int log_vty_init(const char *progname, const char *protoname,
@@ -801,4 +859,7 @@ void log_cmd_init(void)
install_element(CONFIG_NODE, &config_log_filterfile_cmd);
install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
install_element(CONFIG_NODE, &log_immediate_mode_cmd);
+
+ install_element(ENABLE_NODE, &debug_uid_backtrace_cmd);
+ install_element(CONFIG_NODE, &debug_uid_backtrace_cmd);
}
diff --git a/lib/resolver.c b/lib/resolver.c
index 4aba909f25..e3dba5f8ae 100644
--- a/lib/resolver.c
+++ b/lib/resolver.c
@@ -14,7 +14,8 @@
#include <ares.h>
#include <ares_version.h>
-#include "vector.h"
+#include "typesafe.h"
+#include "jhash.h"
#include "thread.h"
#include "lib_errors.h"
#include "resolver.h"
@@ -27,13 +28,78 @@ struct resolver_state {
ares_channel channel;
struct thread_master *master;
struct thread *timeout;
- vector read_threads, write_threads;
};
static struct resolver_state state;
static bool resolver_debug;
-#define THREAD_RUNNING ((struct thread *)-1)
+/* a FD doesn't necessarily map 1:1 to a request; we could be talking to
+ * multiple caches simultaneously, to see which responds fastest.
+ * Theoretically we could also be using the same fd for multiple lookups,
+ * but the c-ares API guarantees an n:1 mapping for fd => channel.
+ *
+ * Either way c-ares makes that decision and we just need to deal with
+ * whatever FDs it gives us.
+ */
+
+DEFINE_MTYPE_STATIC(LIB, ARES_FD, "c-ares (DNS) file descriptor information");
+PREDECL_HASH(resolver_fds);
+
+struct resolver_fd {
+ struct resolver_fds_item itm;
+
+ int fd;
+ struct resolver_state *state;
+ struct thread *t_read, *t_write;
+};
+
+static int resolver_fd_cmp(const struct resolver_fd *a,
+ const struct resolver_fd *b)
+{
+ return numcmp(a->fd, b->fd);
+}
+
+static uint32_t resolver_fd_hash(const struct resolver_fd *item)
+{
+ return jhash_1word(item->fd, 0xacd04c9e);
+}
+
+DECLARE_HASH(resolver_fds, struct resolver_fd, itm, resolver_fd_cmp,
+ resolver_fd_hash);
+
+static struct resolver_fds_head resfds[1] = {INIT_HASH(resfds[0])};
+
+static struct resolver_fd *resolver_fd_get(int fd,
+ struct resolver_state *newstate)
+{
+ struct resolver_fd ref = {.fd = fd}, *res;
+
+ res = resolver_fds_find(resfds, &ref);
+ if (!res && newstate) {
+ res = XCALLOC(MTYPE_ARES_FD, sizeof(*res));
+ res->fd = fd;
+ res->state = newstate;
+ resolver_fds_add(resfds, res);
+
+ if (resolver_debug)
+ zlog_debug("c-ares registered FD %d", fd);
+ }
+ return res;
+}
+
+static void resolver_fd_drop_maybe(struct resolver_fd *resfd)
+{
+ if (resfd->t_read || resfd->t_write)
+ return;
+
+ if (resolver_debug)
+ zlog_debug("c-ares unregistered FD %d", resfd->fd);
+
+ resolver_fds_del(resfds, resfd);
+ XFREE(MTYPE_ARES_FD, resfd);
+}
+
+/* end of FD housekeeping */
static void resolver_update_timeouts(struct resolver_state *r);
@@ -41,9 +107,7 @@ static int resolver_cb_timeout(struct thread *t)
{
struct resolver_state *r = THREAD_ARG(t);
- r->timeout = THREAD_RUNNING;
ares_process(r->channel, NULL, NULL);
- r->timeout = NULL;
resolver_update_timeouts(r);
return 0;
@@ -51,17 +115,16 @@ static int resolver_cb_timeout(struct thread *t)
static int resolver_cb_socket_readable(struct thread *t)
{
- struct resolver_state *r = THREAD_ARG(t);
- int fd = THREAD_FD(t);
- struct thread **t_ptr;
-
- vector_set_index(r->read_threads, fd, THREAD_RUNNING);
- ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
- if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
- t_ptr = (struct thread **)vector_get_index(r->read_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_readable, r, fd,
- t_ptr);
- }
+ struct resolver_fd *resfd = THREAD_ARG(t);
+ struct resolver_state *r = resfd->state;
+
+ thread_add_read(r->master, resolver_cb_socket_readable, resfd,
+ resfd->fd, &resfd->t_read);
+ /* ^ ordering important:
+ * ares_process_fd may transitively call THREAD_OFF(resfd->t_read)
+ * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
+ */
+ ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD);
resolver_update_timeouts(r);
return 0;
@@ -69,17 +132,16 @@ static int resolver_cb_socket_readable(struct thread *t)
static int resolver_cb_socket_writable(struct thread *t)
{
- struct resolver_state *r = THREAD_ARG(t);
- int fd = THREAD_FD(t);
- struct thread **t_ptr;
-
- vector_set_index(r->write_threads, fd, THREAD_RUNNING);
- ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
- if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
- t_ptr = (struct thread **)vector_get_index(r->write_threads, fd);
- thread_add_write(r->master, resolver_cb_socket_writable, r, fd,
- t_ptr);
- }
+ struct resolver_fd *resfd = THREAD_ARG(t);
+ struct resolver_state *r = resfd->state;
+
+ thread_add_write(r->master, resolver_cb_socket_writable, resfd,
+ resfd->fd, &resfd->t_write);
+ /* ^ ordering important:
+ * ares_process_fd may transitively call THREAD_OFF(resfd->t_write)
+ * combined with resolver_fd_drop_maybe, so resfd may be free'd after!
+ */
+ ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd);
resolver_update_timeouts(r);
return 0;
@@ -89,13 +151,11 @@ static void resolver_update_timeouts(struct resolver_state *r)
{
struct timeval *tv, tvbuf;
- if (r->timeout == THREAD_RUNNING)
- return;
-
THREAD_OFF(r->timeout);
tv = ares_timeout(r->channel, NULL, &tvbuf);
if (tv) {
unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+
thread_add_timer_msec(r->master, resolver_cb_timeout, r,
timeoutms, &r->timeout);
}
@@ -105,43 +165,27 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
int writable)
{
struct resolver_state *r = (struct resolver_state *)data;
- struct thread *t, **t_ptr;
-
- if (readable) {
- t = vector_lookup(r->read_threads, fd);
- if (!t) {
- t_ptr = (struct thread **)vector_get_index(
- r->read_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_readable,
- r, fd, t_ptr);
- }
- } else {
- t = vector_lookup(r->read_threads, fd);
- if (t) {
- if (t != THREAD_RUNNING) {
- THREAD_OFF(t);
- }
- vector_unset(r->read_threads, fd);
- }
- }
+ struct resolver_fd *resfd;
- if (writable) {
- t = vector_lookup(r->write_threads, fd);
- if (!t) {
- t_ptr = (struct thread **)vector_get_index(
- r->write_threads, fd);
- thread_add_read(r->master, resolver_cb_socket_writable,
- r, fd, t_ptr);
- }
- } else {
- t = vector_lookup(r->write_threads, fd);
- if (t) {
- if (t != THREAD_RUNNING) {
- THREAD_OFF(t);
- }
- vector_unset(r->write_threads, fd);
- }
- }
+ resfd = resolver_fd_get(fd, (readable || writable) ? r : NULL);
+ if (!resfd)
+ return;
+
+ assert(resfd->state == r);
+
+ if (!readable)
+ THREAD_OFF(resfd->t_read);
+ else if (!resfd->t_read)
+ thread_add_read(r->master, resolver_cb_socket_readable, resfd,
+ fd, &resfd->t_read);
+
+ if (!writable)
+ THREAD_OFF(resfd->t_write);
+ else if (!resfd->t_write)
+ thread_add_write(r->master, resolver_cb_socket_writable, resfd,
+ fd, &resfd->t_write);
+
+ resolver_fd_drop_maybe(resfd);
}
@@ -271,8 +315,6 @@ void resolver_init(struct thread_master *tm)
struct ares_options ares_opts;
state.master = tm;
- state.read_threads = vector_init(1);
- state.write_threads = vector_init(1);
ares_opts = (struct ares_options){
.sock_state_cb = &ares_socket_cb,
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 918a2ebdcb..d7d4a9a81f 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -166,7 +166,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_address, match_ip_address_cmd,
- "match ip address WORD$name",
+ "match ip address ACCESSLIST4_NAME$name",
MATCH_STR
IP_STR
"Match address of route\n"
@@ -186,7 +186,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ip_address, no_match_ip_address_cmd,
- "no match ip address [WORD]",
+ "no match ip address [ACCESSLIST4_NAME]",
NO_STR
MATCH_STR
IP_STR
@@ -243,7 +243,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ip_next_hop, match_ip_next_hop_cmd,
- "match ip next-hop WORD$name",
+ "match ip next-hop ACCESSLIST4_NAME$name",
MATCH_STR
IP_STR
"Match next-hop address of route\n"
@@ -263,7 +263,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ip_next_hop, no_match_ip_next_hop_cmd,
- "no match ip next-hop [WORD]",
+ "no match ip next-hop [ACCESSLIST4_NAME]",
NO_STR
MATCH_STR
IP_STR
@@ -358,7 +358,7 @@ DEFPY_YANG(
DEFPY_YANG(
match_ipv6_address, match_ipv6_address_cmd,
- "match ipv6 address WORD$name",
+ "match ipv6 address ACCESSLIST6_NAME$name",
MATCH_STR
IPV6_STR
"Match IPv6 address of route\n"
@@ -378,7 +378,7 @@ DEFPY_YANG(
DEFPY_YANG(
no_match_ipv6_address, no_match_ipv6_address_cmd,
- "no match ipv6 address [WORD]",
+ "no match ipv6 address [ACCESSLIST6_NAME]",
NO_STR
MATCH_STR
IPV6_STR
diff --git a/lib/typerb.h b/lib/typerb.h
index d22d864aae..75a1de77b3 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -20,6 +20,7 @@
#ifndef _FRR_TYPERB_H
#define _FRR_TYPERB_H
+#include <string.h>
#include "typesafe.h"
#ifdef __cplusplus
diff --git a/lib/typesafe.c b/lib/typesafe.c
index f90b59daf0..3b65a2d02a 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
#include "typesafe.h"
#include "memory.h"
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 44c42ffbca..b284397d98 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -20,7 +20,6 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
-#include <assert.h>
#include "compiler.h"
#ifdef __cplusplus
diff --git a/lib/vector.c b/lib/vector.c
index 38f9b1b85f..5497c24280 100644
--- a/lib/vector.c
+++ b/lib/vector.c
@@ -136,17 +136,6 @@ int vector_set_index(vector v, unsigned int i, void *val)
return i;
}
-/* Make a specified index slot active and return its address. */
-void **vector_get_index(vector v, unsigned int i)
-{
- vector_ensure(v, i);
-
- if (v->active <= i)
- v->active = i + 1;
-
- return &v->index[i];
-}
-
/* Look up vector. */
void *vector_lookup(vector v, unsigned int i)
{
diff --git a/lib/vector.h b/lib/vector.h
index 6208be1cc7..71c497a1b7 100644
--- a/lib/vector.h
+++ b/lib/vector.h
@@ -55,7 +55,6 @@ extern void vector_ensure(vector v, unsigned int num);
extern int vector_empty_slot(vector v);
extern int vector_set(vector v, void *val);
extern int vector_set_index(vector v, unsigned int i, void *val);
-extern void **vector_get_index(vector v, unsigned int i);
extern void vector_unset(vector v, unsigned int i);
extern void vector_unset_value(vector v, void *val);
extern void vector_remove(vector v, unsigned int ix);
diff --git a/lib/xref.c b/lib/xref.c
index a41f91a228..0d3549d062 100644
--- a/lib/xref.c
+++ b/lib/xref.c
@@ -35,6 +35,8 @@
struct xref_block *xref_blocks;
static struct xref_block **xref_block_last = &xref_blocks;
+struct xrefdata_uid_head xrefdata_uid = INIT_RBTREE_UNIQ(xrefdata_uid);
+
static void base32(uint8_t **inpos, int *bitpos,
char *out, size_t n_chars)
{
@@ -109,6 +111,8 @@ static void xref_add_one(const struct xref *xref)
base32(&h, &bitpos, &xrefdata->uid[0], 5);
xrefdata->uid[5] = '-';
base32(&h, &bitpos, &xrefdata->uid[6], 5);
+
+ xrefdata_uid_add(&xrefdata_uid, xrefdata);
}
void xref_gcc_workaround(const struct xref *xref)
diff --git a/lib/xref.h b/lib/xref.h
index 6cff1a3769..0e3f00f690 100644
--- a/lib/xref.h
+++ b/lib/xref.h
@@ -22,6 +22,7 @@
#include <limits.h>
#include <errno.h>
#include "compiler.h"
+#include "typesafe.h"
#ifdef __cplusplus
extern "C" {
@@ -63,6 +64,8 @@ struct xref {
/* type-specific bits appended by embedding this struct */
};
+PREDECL_RBTREE_UNIQ(xrefdata_uid);
+
struct xrefdata {
/* pointer back to the const part; this will be initialized at
* program startup by xref_block_add(). (Creating structs with
@@ -88,8 +91,18 @@ struct xrefdata {
uint32_t hashu32[2];
/* -- 32 bytes (on 64bit) -- */
+ struct xrefdata_uid_item xui;
};
+static inline int xrefdata_uid_cmp(const struct xrefdata *a,
+ const struct xrefdata *b)
+{
+ return strcmp(a->uid, b->uid);
+}
+
+DECLARE_RBTREE_UNIQ(xrefdata_uid, struct xrefdata, xui, xrefdata_uid_cmp);
+extern struct xrefdata_uid_head xrefdata_uid;
+
/* linker "magic" is used to create an array of pointers to struct xref.
* the result is a contiguous block of pointers, each pointing to an xref
* somewhere in the code. The linker gives us start and end pointers, we
diff --git a/lib/zlog.c b/lib/zlog.c
index 6fd52cae62..1b0751559d 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -47,12 +47,19 @@
#include <mach/mach_traps.h>
#endif
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <dlfcn.h>
+#endif
+
#include "memory.h"
#include "atomlist.h"
#include "printfrr.h"
#include "frrcu.h"
#include "zlog.h"
#include "libfrr_trace.h"
+#include "thread.h"
DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message");
DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer");
@@ -508,6 +515,87 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref,
XFREE(MTYPE_LOG_MESSAGE, msg->text);
}
+static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio)
+{
+ struct thread *tc = pthread_getspecific(thread_current);
+ const char *uid = xref->xref.xrefdata->uid;
+ bool found_thread = false;
+
+ zlog(prio, "| (%s) message in thread %jd, at %s(), %s:%d", uid,
+ zlog_gettid(), xref->xref.func, xref->xref.file, xref->xref.line);
+
+#ifdef HAVE_LIBUNWIND
+ const char *threadfunc = tc ? tc->xref->funcname : NULL;
+ bool found_caller = false;
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_word_t ip, off, sp;
+ Dl_info dlinfo;
+
+ unw_getcontext(&uc);
+
+ unw_init_local(&cursor, &uc);
+ while (unw_step(&cursor) > 0) {
+ char buf[96], name[128] = "?";
+ bool is_thread = false;
+
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ if (unw_is_signal_frame(&cursor))
+ zlog(prio, "| (%s) ---- signal ----", uid);
+
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) {
+ if (!strcmp(buf, xref->xref.func))
+ found_caller = true;
+ if (threadfunc && !strcmp(buf, threadfunc))
+ found_thread = is_thread = true;
+
+ snprintf(name, sizeof(name), "%s+%#lx", buf, (long)off);
+ }
+
+ if (!found_caller)
+ continue;
+
+ if (dladdr((void *)ip, &dlinfo))
+ zlog(prio, "| (%s) %-36s %16lx+%08lx %16lx %s", uid,
+ name, (long)dlinfo.dli_fbase,
+ (long)ip - (long)dlinfo.dli_fbase, (long)sp,
+ dlinfo.dli_fname);
+ else
+ zlog(prio, "| (%s) %-36s %16lx %16lx", uid, name,
+ (long)ip, (long)sp);
+
+ if (is_thread)
+ zlog(prio, "| (%s) ^- scheduled from %s(), %s:%u", uid,
+ tc->xref->xref.func, tc->xref->xref.file,
+ tc->xref->xref.line);
+ }
+#elif defined(HAVE_GLIBC_BACKTRACE)
+ void *frames[64];
+ char **names = NULL;
+ int n_frames, i;
+
+ n_frames = backtrace(frames, array_size(frames));
+ if (n_frames < 0)
+ n_frames = 0;
+ if (n_frames)
+ names = backtrace_symbols(frames, n_frames);
+
+ for (i = 0; i < n_frames; i++) {
+ void *retaddr = frames[i];
+ char *loc = names[i];
+
+ zlog(prio, "| (%s) %16lx %-36s", uid, (long)retaddr, loc);
+ }
+ free(names);
+#endif
+ if (!found_thread && tc)
+ zlog(prio, "| (%s) scheduled from %s(), %s:%u", uid,
+ tc->xref->xref.func, tc->xref->xref.file,
+ tc->xref->xref.line);
+}
+
void vzlogx(const struct xref_logmsg *xref, int prio,
const char *fmt, va_list ap)
{
@@ -545,6 +633,15 @@ void vzlogx(const struct xref_logmsg *xref, int prio,
vzlog_tls(zlog_tls, xref, prio, fmt, ap);
else
vzlog_notls(xref, prio, fmt, ap);
+
+ if (xref) {
+ struct xrefdata_logmsg *xrdl;
+
+ xrdl = container_of(xref->xref.xrefdata, struct xrefdata_logmsg,
+ xrefdata);
+ if (xrdl->fl_print_bt)
+ zlog_backtrace_msg(xref, prio);
+ }
}
void zlog_sigsafe(const char *text, size_t len)
diff --git a/lib/zlog.h b/lib/zlog.h
index d9c8952ac5..6e84fe8923 100644
--- a/lib/zlog.h
+++ b/lib/zlog.h
@@ -54,10 +54,14 @@ struct xref_logmsg {
const char *args;
};
+/* whether flag was added in config mode or enable mode */
+#define LOGMSG_FLAG_EPHEMERAL (1 << 0)
+#define LOGMSG_FLAG_PERSISTENT (1 << 1)
+
struct xrefdata_logmsg {
struct xrefdata xrefdata;
- /* nothing more here right now */
+ uint8_t fl_print_bt;
};
/* These functions are set up to write to stdout/stderr without explicit
@@ -94,15 +98,19 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
#define _zlog_ecref(ec_, prio, msg, ...) \
do { \
- static struct xrefdata _xrefdata = { \
- .xref = NULL, \
- .uid = {}, \
- .hashstr = (msg), \
- .hashu32 = {(prio), (ec_)}, \
+ static struct xrefdata_logmsg _xrefdata = { \
+ .xrefdata = \
+ { \
+ .xref = NULL, \
+ .uid = {}, \
+ .hashstr = (msg), \
+ .hashu32 = {(prio), (ec_)}, \
+ }, \
}; \
static const struct xref_logmsg _xref __attribute__( \
(used)) = { \
- .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \
+ .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \
+ __func__), \
.fmtstring = (msg), \
.priority = (prio), \
.ec = (ec_), \