From e20bef69ccc4a85ef62359ee539c9db2dbe09127 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 7 Jan 2023 20:18:44 +0100 Subject: Filter: Change linearization of branches in switch instruction Most branching instructions (FI_CONDITION, FI_AND, FI_OR) linearize its branches in a recursive way, while FI_SWITCH branches are linearized from parser even before the switch instruction is allocated. Change linearization of FI_SWITCH branches to make it similar to other branching instructions. This also fixes an issue with constant switch evaluation, where linearized branch is mistaken for non-linearized during switch construction. Thanks to Jiten Kumar Pathy for the bugreport. --- filter/config.Y | 7 +++---- filter/data.h | 1 + filter/f-inst.c | 25 ++++++++++++++++++++++--- filter/tree.c | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index 68ee1a84..1d9d9aa9 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -676,16 +676,15 @@ switch_body: /* EMPTY */ { $$ = NULL; } | switch_body switch_items ':' cmds_scoped { /* Fill data fields */ struct f_tree *t; - struct f_line *line = f_linearize($4, 0); for (t = $2; t; t = t->left) - t->data = line; + t->data = $4; $$ = f_merge_items($1, $2); } | switch_body ELSECOL cmds_scoped { struct f_tree *t = f_new_tree(); t->from.type = t->to.type = T_VOID; t->right = t; - t->data = f_linearize($3, 0); + t->data = $3; $$ = f_merge_items($1, t); } ; @@ -972,7 +971,7 @@ cmd: } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } | CASE term '{' switch_body '}' { - $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); + $$ = f_new_inst(FI_SWITCH, $2, $4); } | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); } diff --git a/filter/data.h b/filter/data.h index 5edeaedb..700609e9 100644 --- a/filter/data.h +++ b/filter/data.h @@ -198,6 +198,7 @@ struct f_trie_walk_state struct f_tree *f_new_tree(void); struct f_tree *build_tree(struct f_tree *); const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); +const struct f_tree *find_tree_linear(const struct f_tree *t, const struct f_val *val); int same_tree(const struct f_tree *t0, const struct f_tree *t2); int tree_node_count(const struct f_tree *t); void tree_format(const struct f_tree *t, buffer *buf); diff --git a/filter/f-inst.c b/filter/f-inst.c index 9a3a22ab..2d2a30e4 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -1285,14 +1285,33 @@ FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree); + FID_LINEARIZE_BODY() + /* Linearize all branches in switch */ + struct f_inst *last_inst = NULL; + struct f_line *last_line = NULL; + for (struct f_tree *t = whati->tree; t; t = t->left) + { + if (t->data != last_inst) + { + last_inst = t->data; + last_line = f_linearize(t->data, 0); + } + + t->data = last_line; + } + + /* Balance the tree */ + item->tree = build_tree(whati->tree); + FID_ITERATE_BODY() - tree_walk(whati->tree, f_add_tree_lines, fit); + tree_walk(whati->tree, f_add_tree_lines, fit); FID_INTERPRET_BODY() - const struct f_tree *t = find_tree(tree, &v1); + /* In parse-time use find_tree_linear(), in runtime use find_tree() */ + const struct f_tree *t = FID_HIC(,find_tree,find_tree_linear)(tree, &v1); if (!t) { v1.type = T_VOID; - t = find_tree(tree, &v1); + t = FID_HIC(,find_tree,find_tree_linear)(tree, &v1); if (!t) { debug( "No else statement?\n"); FID_HIC(,break,return NULL); diff --git a/filter/tree.c b/filter/tree.c index 97bf7dae..25cf93e4 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -38,6 +38,26 @@ find_tree(const struct f_tree *t, const struct f_val *val) return find_tree(t->left, val); } +/** + * find_tree_linear + * @t: tree to search in + * @val: value to find + * + * Search for given value in the degenerated linear tree, which is generated by + * parser before build_tree() is applied. The tree is not sorted and all nodes + * are linked by left ptr. + */ +const struct f_tree * +find_tree_linear(const struct f_tree *t, const struct f_val *val) +{ + for (; t; t = t->left) + if ((val_compare(&(t->from), val) != 1) && + (val_compare(&(t->to), val) != -1)) + return t; + + return NULL; +} + static struct f_tree * build_tree_rec(struct f_tree **buf, int l, int h) { -- cgit v1.2.3 From 64a2b7aaa303be0b407508747bfc96c1c656f1e2 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Thu, 12 Jan 2023 17:40:53 +0100 Subject: Log message before aborting Log message before aborting due to watchdog timeout. We have to use async-safe write to debug log, as it is done in signal handler. Minor changes from committer. --- lib/birdlib.h | 1 + sysdep/unix/io.c | 2 ++ sysdep/unix/log.c | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/lib/birdlib.h b/lib/birdlib.h index 81d4908a..e03bd0b2 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -160,6 +160,7 @@ void bug(const char *msg, ...) NORET; #define L_BUG "\011" /* BIRD bugs */ void debug(const char *msg, ...); /* Printf to debug output */ +void debug_safe(const char *msg); /* Printf to debug output, async-safe */ /* Debugging */ diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 810e782d..e131ca41 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -2128,6 +2128,8 @@ watchdog_sigalrm(int sig UNUSED) config->latency_limit = 0xffffffff; io_update_time(); + debug_safe("Watchdog timer timed out\n"); + /* We want core dump */ abort(); } diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 4e9df069..53122aee 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -31,6 +31,7 @@ #include "lib/lists.h" #include "sysdep/unix/unix.h" +static int dbg_fd = -1; static FILE *dbgf; static list *current_log_list; static char *current_syslog_name; /* NULL -> syslog closed */ @@ -324,6 +325,21 @@ debug(const char *msg, ...) va_end(args); } +/** + * debug_safe - async-safe write to debug output + * @msg: a string message + * + * This function prints the message @msg to the debugging output in a + * way that is async safe and can be used in signal handlers. No newline + * character is appended. + */ +void +debug_safe(const char *msg) +{ + if (dbg_fd >= 0) + write(dbg_fd, msg, strlen(msg)); +} + static list * default_log_list(int initial, const char **syslog_name) { @@ -422,8 +438,10 @@ done: void log_init_debug(char *f) { + dbg_fd = -1; if (dbgf && dbgf != stderr) fclose(dbgf); + if (!f) dbgf = NULL; else if (!*f) @@ -434,6 +452,10 @@ log_init_debug(char *f) fprintf(stderr, "bird: Unable to open debug file %s: %s\n", f, strerror(errno)); exit(1); } + if (dbgf) + { setvbuf(dbgf, NULL, _IONBF, 0); + dbg_fd = fileno(dbgf); + } } -- cgit v1.2.3 From 7fb23041a52d01754c53ba963e2282e524813364 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 13 Jan 2023 13:17:46 +0100 Subject: BSD: Add support for kernel route metric Add support for kernel route metric/priority, exported as krt_metric attribute, like in Linux. This should also fix issues with overwriting or removing system routes. --- sysdep/bsd/krt-sock.Y | 10 +++++++++- sysdep/bsd/krt-sock.c | 39 +++++++++++++++++++++++++++++++++++++-- sysdep/bsd/krt-sys.h | 2 ++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/sysdep/bsd/krt-sock.Y b/sysdep/bsd/krt-sock.Y index 8581bd43..a03d6df5 100644 --- a/sysdep/bsd/krt-sock.Y +++ b/sysdep/bsd/krt-sock.Y @@ -10,7 +10,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(KERNEL, TABLE) +CF_KEYWORDS(KERNEL, TABLE, METRIC) CF_GRAMMAR @@ -25,6 +25,14 @@ kern_sys_item: THIS_KRT->sys.table_id = $3; } + | METRIC expr { + if ($2 && !krt_max_metric) + cf_error("Kernel route metric not supported"); + if ($2 > krt_max_metric) + cf_error("Kernel table id must be in range 0-%u", krt_max_metric); + + THIS_KRT->sys.metric = $2; + } ; CF_CODE diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 47f5cf59..540c246f 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -47,6 +47,11 @@ const int rt_default_ecmp = 0; * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it * is handled implicitly by changing default table using setfib() syscall. * + * OpenBSD allows to use route metric. The behavior is controlled by these macro + * KRT_USE_METRIC, which enables use of rtm_priority in route send/recevive. + * There is also KRT_DEFAULT_METRIC and KRT_MAX_METRIC for default and maximum + * metric values. + * * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets @@ -63,6 +68,9 @@ const int rt_default_ecmp = 0; #ifdef __OpenBSD__ #define KRT_MAX_TABLES (RT_TABLEID_MAX+1) +#define KRT_USE_METRIC +#define KRT_MAX_METRIC 255 +#define KRT_DEFAULT_METRIC 56 #define KRT_SHARED_SOCKET #define KRT_USE_SYSCTL_7 #endif @@ -71,6 +79,14 @@ const int rt_default_ecmp = 0; #define KRT_MAX_TABLES 1 #endif +#ifndef KRT_MAX_METRIC +#define KRT_MAX_METRIC 0 +#endif + +#ifndef KRT_DEFAULT_METRIC +#define KRT_DEFAULT_METRIC 0 +#endif + /* Dynamic max number of tables */ @@ -143,6 +159,10 @@ static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2]; #endif +/* Make it available to parser code */ +const uint krt_max_metric = KRT_MAX_METRIC; + + /* Route socket message processing */ int @@ -231,6 +251,10 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) msg.rtm.rtm_tableid = KRT_CF->sys.table_id; #endif +#ifdef KRT_USE_METRIC + msg.rtm.rtm_priority = KRT_CF->sys.metric; +#endif + #ifdef RTF_REJECT if(a->dest == RTD_UNREACHABLE) msg.rtm.rtm_flags |= RTF_REJECT; @@ -586,7 +610,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) e = rte_get_temp(&a, p->p.main_source); e->net = net; - ea_list *ea = alloca(sizeof(ea_list) + 1 * sizeof(eattr)); + ea_list *ea = alloca(sizeof(ea_list) + 2 * sizeof(eattr)); *ea = (ea_list) { .count = 1, .next = e->attrs->eattrs }; e->attrs->eattrs = ea; @@ -596,6 +620,15 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) .u.data = src2, }; +#ifdef KRT_USE_METRIC + ea->count++; + ea->attrs[1] = (eattr) { + .id = EA_KRT_METRIC, + .type = EAF_TYPE_INT, + .u.data = msg->rtm.rtm_priority, + }; +#endif + if (scan) krt_got_route(p, e, src); else @@ -1155,7 +1188,7 @@ krt_sys_shutdown(struct krt_proto *p) int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o) { - return n->sys.table_id == o->sys.table_id; + return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric); } void @@ -1168,11 +1201,13 @@ krt_sys_preconfig(struct config *c UNUSED) void krt_sys_init_config(struct krt_config *c) { c->sys.table_id = 0; /* Default table */ + c->sys.metric = KRT_DEFAULT_METRIC; } void krt_sys_copy_config(struct krt_config *d, struct krt_config *s) { d->sys.table_id = s->sys.table_id; + d->sys.metric = s->sys.metric; } diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h index 57501884..198373c0 100644 --- a/sysdep/bsd/krt-sys.h +++ b/sysdep/bsd/krt-sys.h @@ -32,9 +32,11 @@ static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_c /* Kernel routes */ extern uint krt_max_tables; +extern const uint krt_max_metric; struct krt_params { int table_id; /* Kernel table ID we sync with */ + u32 metric; /* Kernel metric used for all routes */ }; struct krt_state { -- cgit v1.2.3