summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/conf.h1
-rw-r--r--doc/bird.sgml2
-rw-r--r--filter/config.Y19
-rw-r--r--filter/data.h1
-rw-r--r--filter/decl.m424
-rw-r--r--filter/f-inst.c24
-rw-r--r--filter/filter.c63
-rw-r--r--filter/filter_test.c4
-rw-r--r--filter/test.conf1
-rw-r--r--filter/tree_test.c5
-rw-r--r--filter/trie_test.c77
-rw-r--r--lib/bitmap_test.c3
-rw-r--r--lib/buffer_test.c1
-rw-r--r--lib/event.c2
-rw-r--r--lib/event_test.c1
-rw-r--r--lib/flowspec_test.c11
-rw-r--r--lib/hash.h6
-rw-r--r--lib/hash_test.c1
-rw-r--r--lib/lists.h1
-rw-r--r--lib/mempool.c48
-rw-r--r--lib/resource.c3
-rw-r--r--lib/resource.h16
-rw-r--r--lib/slab.c17
-rw-r--r--lib/timer.c1
-rw-r--r--nest/a-path_test.c30
-rw-r--r--nest/a-set_test.c51
-rw-r--r--nest/cmds.c5
-rw-r--r--nest/config.Y2
-rw-r--r--nest/proto-hooks.c40
-rw-r--r--nest/proto.c9
-rw-r--r--nest/protocol.h19
-rw-r--r--nest/route.h76
-rw-r--r--nest/rt-attr.c37
-rw-r--r--nest/rt-dev.c4
-rw-r--r--nest/rt-show.c13
-rw-r--r--nest/rt-table.c367
-rw-r--r--proto/babel/babel.c111
-rw-r--r--proto/babel/babel.h1
-rw-r--r--proto/bfd/io.c2
-rw-r--r--proto/bgp/attrs.c91
-rw-r--r--proto/bgp/bgp.c24
-rw-r--r--proto/bgp/bgp.h12
-rw-r--r--proto/bgp/packets.c17
-rw-r--r--proto/mrt/mrt.c10
-rw-r--r--proto/ospf/iface.c3
-rw-r--r--proto/ospf/ospf.c82
-rw-r--r--proto/ospf/rt.c54
-rw-r--r--proto/perf/perf.c4
-rw-r--r--proto/pipe/pipe.c30
-rw-r--r--proto/radv/radv.c4
-rw-r--r--proto/rip/rip.c80
-rw-r--r--proto/rip/rip.h1
-rw-r--r--proto/rpki/rpki.c6
-rw-r--r--proto/static/static.c13
-rw-r--r--sysdep/bsd/krt-sock.c19
-rw-r--r--sysdep/linux/netlink.c29
-rw-r--r--sysdep/unix/alloc.c193
-rw-r--r--sysdep/unix/io.c23
-rw-r--r--sysdep/unix/krt.c101
-rw-r--r--sysdep/unix/krt.h7
-rw-r--r--sysdep/unix/log.c15
-rw-r--r--sysdep/unix/main.c9
-rw-r--r--test/birdtest.c8
-rw-r--r--test/bt-utils.c1
64 files changed, 842 insertions, 1093 deletions
diff --git a/conf/conf.h b/conf/conf.h
index 3bc37959..55cb9c58 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -35,6 +35,7 @@ struct config {
u32 proto_default_debug; /* Default protocol debug mask */
u32 proto_default_mrtdump; /* Default protocol mrtdump mask */
u32 channel_default_debug; /* Default channel debug mask */
+ u16 filter_vstk, filter_estk; /* Filter stack depth */
struct timeformat tf_route; /* Time format for 'show route' */
struct timeformat tf_proto; /* Time format for 'show protocol' */
struct timeformat tf_log; /* Time format for the logfile */
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 1d5ae056..4df1d94f 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1747,7 +1747,7 @@ Common route attributes are:
<tag><label id="rta-source"><m/enum/ source</tag>
what protocol has told me about this route. Possible values:
- <cf/RTS_DUMMY/, <cf/RTS_STATIC/, <cf/RTS_INHERIT/, <cf/RTS_DEVICE/,
+ <cf/RTS_STATIC/, <cf/RTS_INHERIT/, <cf/RTS_DEVICE/,
<cf/RTS_RIP/, <cf/RTS_OSPF/, <cf/RTS_OSPF_IA/, <cf/RTS_OSPF_EXT1/,
<cf/RTS_OSPF_EXT2/, <cf/RTS_BGP/, <cf/RTS_PIPE/, <cf/RTS_BABEL/.
diff --git a/filter/config.Y b/filter/config.Y
index 8916ea97..15b77761 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -248,10 +248,6 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const
setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
getter = f_new_inst(FI_VAR_GET, lval->sym);
break;
- case F_LVAL_PREFERENCE:
- setter = f_new_inst(FI_PREF_SET, expr);
- getter = f_new_inst(FI_PREF_GET);
- break;
case F_LVAL_SA:
setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
getter = f_new_inst(FI_RTA_GET, lval->sa);
@@ -290,7 +286,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
MIN, MAX,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
- BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
+ BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
%nonassoc THEN
%nonassoc ELSE
@@ -314,6 +310,12 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
CF_GRAMMAR
+conf: FILTER STACKS expr expr ';' {
+ new_config->filter_vstk = $3;
+ new_config->filter_estk = $4;
+ }
+ ;
+
conf: filter_def ;
filter_def:
FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
@@ -753,6 +755,7 @@ static_attr:
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
| WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
+ | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); }
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
;
@@ -779,8 +782,6 @@ term:
| constant { $$ = $1; }
| constructor { $$ = $1; }
- | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
-
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
| dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
@@ -878,9 +879,6 @@ cmd:
cf_error( "This static attribute is read-only.");
$$ = f_new_inst(FI_RTA_SET, $3, $1);
}
- | PREFERENCE '=' term ';' {
- $$ = f_new_inst(FI_PREF_SET, $3);
- }
| UNSET '(' dynamic_attr ')' ';' {
$$ = f_new_inst(FI_EA_UNSET, $3);
}
@@ -923,7 +921,6 @@ get_cf_position:
lvalue:
CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
- | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
diff --git a/filter/data.h b/filter/data.h
index 4cb6b7a8..6d588204 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -100,6 +100,7 @@ enum f_sa_code {
SA_IFNAME,
SA_IFINDEX,
SA_WEIGHT,
+ SA_PREF,
SA_GW_MPLS,
} PACKED;
diff --git a/filter/decl.m4 b/filter/decl.m4
index 5242c04c..44537aaa 100644
--- a/filter/decl.m4
+++ b/filter/decl.m4
@@ -32,6 +32,7 @@ m4_divert(-1)m4_dnl
#
# 101 content of per-inst struct
# 102 constructor arguments
+# 110 constructor attributes
# 103 constructor body
# 104 dump line item content
# (there may be nothing in dump-line content and
@@ -45,6 +46,7 @@ m4_divert(-1)m4_dnl
# Here are macros to allow you to _divert to the right directions.
m4_define(FID_STRUCT_IN, `m4_divert(101)')
m4_define(FID_NEW_ARGS, `m4_divert(102)')
+m4_define(FID_NEW_ATTRIBUTES, `m4_divert(110)')
m4_define(FID_NEW_BODY, `m4_divert(103)')
m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])')
m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
@@ -106,15 +108,18 @@ FID_STRUCT_IN()m4_dnl
struct f_inst * f$1;
FID_NEW_ARGS()m4_dnl
, struct f_inst * f$1
+FID_NEW_ATTRIBUTES()m4_dnl
+NONNULL(m4_eval($1+1))
FID_NEW_BODY()m4_dnl
whati->f$1 = f$1;
-for (const struct f_inst *child = f$1; child; child = child->next) {
- what->size += child->size;
+const struct f_inst *child$1 = f$1;
+do {
+ what->size += child$1->size;
FID_IFCONST([[
- if (child->fi_code != FI_CONSTANT)
+ if (child$1->fi_code != FI_CONSTANT)
constargs = 0;
]])
-}
+} while (child$1 = child$1->next);
FID_LINEARIZE_BODY
pos = linearize(dest, whati->f$1, pos);
FID_INTERPRET_BODY()')
@@ -190,6 +195,7 @@ FID_INTERPRET_BODY()')
# that was needed in the former implementation.
m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()')
m4_define(LINEX_, `do {
+ if (fstk->ecnt + 1 >= fstk->elen) runtime("Filter execution stack overflow");
fstk->estk[fstk->ecnt].pos = 0;
fstk->estk[fstk->ecnt].line = $1;
fstk->estk[fstk->ecnt].ventry = fstk->vcnt;
@@ -227,7 +233,7 @@ FID_INTERPRET_BODY()')
# state the result and put it to the right place.
m4_define(RESULT, `RESULT_TYPE([[$1]]) RESULT_([[$1]],[[$2]],[[$3]])')
m4_define(RESULT_, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
-m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]],
+m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; f_vcnt_check_overflow(1); fstk->vcnt++; } while (0)]],
[[return fi_constant(what, $1)]])')
m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])')
@@ -309,7 +315,9 @@ m4_undivert(107)m4_dnl
FID_NEW()m4_dnl Constructor and interpreter code together
FID_HIC(
[[m4_dnl Public declaration of constructor in H file
-struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
+struct f_inst *
+m4_undivert(110)m4_dnl
+f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
m4_undivert(102)m4_dnl
);]],
[[m4_dnl The one case in The Big Switch inside interpreter
@@ -321,7 +329,9 @@ m4_undivert(102)m4_dnl
break;
]],
[[m4_dnl Constructor itself
-struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
+struct f_inst *
+m4_undivert(110)m4_dnl
+f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
m4_undivert(102)m4_dnl
)
{
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 901d2939..83d86295 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -526,13 +526,14 @@
case SA_FROM: RESULT(sa.f_type, ip, rta->from); break;
case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break;
case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
- case SA_PROTO: RESULT(sa.f_type, s, rta->src->proto->name); break;
+ case SA_PROTO: RESULT(sa.f_type, s, (*fs->rte)->src->proto->name); break;
case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break;
case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break;
case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break;
+ case SA_PREF: RESULT(sa.f_type, i, rta->pref); break;
case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
default:
@@ -561,7 +562,7 @@
{
ip_addr ip = v1.val.ip;
struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
- neighbor *n = neigh_find(rta->src->proto, ip, ifa, 0);
+ neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, 0);
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
@@ -637,6 +638,10 @@
}
break;
+ case SA_PREF:
+ rta->pref = v1.val.i;
+ break;
+
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
@@ -804,20 +809,6 @@
}
}
- INST(FI_PREF_GET, 0, 1) {
- ACCESS_RTE;
- RESULT(T_INT, i, (*fs->rte)->pref);
- }
-
- INST(FI_PREF_SET, 1, 0) {
- ACCESS_RTE;
- ARG(1,T_INT);
- if (v1.val.i > 0xFFFF)
- runtime( "Setting preference value out of bounds" );
- f_rte_cow(fs);
- (*fs->rte)->pref = v1.val.i;
- }
-
INST(FI_LENGTH, 1, 1) { /* Get length of */
ARG_ANY(1);
switch(v1.type) {
@@ -1103,6 +1094,7 @@
curline.vbase = curline.ventry;
/* Storage for local variables */
+ f_vcnt_check_overflow(sym->function->vars);
memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
fstk->vcnt += sym->function->vars;
}
diff --git a/filter/filter.c b/filter/filter.c
index e505d570..7004b96d 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -50,30 +50,28 @@ enum f_exception {
FE_RETURN = 0x1,
};
-
-struct filter_stack {
- /* Value stack for execution */
-#define F_VAL_STACK_MAX 4096
- uint vcnt; /* Current value stack size; 0 for empty */
- uint ecnt; /* Current execute stack size; 0 for empty */
-
- struct f_val vstk[F_VAL_STACK_MAX]; /* The stack itself */
-
- /* Instruction stack for execution */
-#define F_EXEC_STACK_MAX 4096
- struct {
- const struct f_line *line; /* The line that is being executed */
- uint pos; /* Instruction index in the line */
- uint ventry; /* Value stack depth on entry */
- uint vbase; /* Where to index variable positions from */
- enum f_exception emask; /* Exception mask */
- } estk[F_EXEC_STACK_MAX];
+struct filter_exec_stack {
+ const struct f_line *line; /* The line that is being executed */
+ uint pos; /* Instruction index in the line */
+ uint ventry; /* Value stack depth on entry */
+ uint vbase; /* Where to index variable positions from */
+ enum f_exception emask; /* Exception mask */
};
/* Internal filter state, to be allocated on stack when executing filters */
struct filter_state {
/* Stacks needed for execution */
- struct filter_stack *stack;
+ struct filter_stack {
+ /* Current filter stack depth */
+
+ /* Value stack */
+ uint vcnt, vlen;
+ struct f_val *vstk;
+
+ /* Instruction stack for execution */
+ uint ecnt, elen;
+ struct filter_exec_stack *estk;
+ } stack;
/* The route we are processing. This may be NULL to indicate no route available. */
struct rte **rte;
@@ -95,10 +93,13 @@ struct filter_state {
};
_Thread_local static struct filter_state filter_state;
-_Thread_local static struct filter_stack filter_stack;
void (*bt_assert_hook)(int result, const struct f_line_item *assert);
+#define _f_stack_init(fs, px, def) ((fs).stack.px##stk = alloca(sizeof(*(fs).stack.px##stk) * ((fs).stack.px##len = (config && config->filter_##px##stk) ? config->filter_##px##stk : (def))))
+
+#define f_stack_init(fs) ( _f_stack_init(fs, v, 128), _f_stack_init(fs, e, 128) )
+
static inline void f_cache_eattrs(struct filter_state *fs)
{
fs->eattrs = &((*fs->rte)->attrs->eattrs);
@@ -163,15 +164,17 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
ASSERT(line->args == 0);
/* Initialize the filter stack */
- struct filter_stack *fstk = fs->stack;
+ struct filter_stack *fstk = &fs->stack;
fstk->vcnt = line->vars;
memset(fstk->vstk, 0, sizeof(struct f_val) * line->vars);
/* The same as with the value stack. Not resetting the stack for performance reasons. */
fstk->ecnt = 1;
- fstk->estk[0].line = line;
- fstk->estk[0].pos = 0;
+ fstk->estk[0] = (struct filter_exec_stack) {
+ .line = line,
+ .pos = 0,
+ };
#define curline fstk->estk[fstk->ecnt-1]
@@ -191,6 +194,8 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
#define v2 vv(1)
#define v3 vv(2)
+#define f_vcnt_check_overflow(n) do { if (fstk->vcnt + n >= fstk->vlen) runtime("Filter execution stack overflow"); } while (0)
+
#define runtime(fmt, ...) do { \
if (!(fs->flags & FF_SILENT)) \
log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
@@ -276,12 +281,13 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
/* Initialize the filter state */
filter_state = (struct filter_state) {
- .stack = &filter_stack,
.rte = rte,
.pool = tmp_pool,
.flags = flags,
};
+ f_stack_init(filter_state);
+
LOG_BUFFER_INIT(filter_state.buf);
/* Run the interpreter itself */
@@ -340,11 +346,12 @@ enum filter_return
f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
{
filter_state = (struct filter_state) {
- .stack = &filter_stack,
.rte = rte,
.pool = tmp_pool,
};
+ f_stack_init(filter_state);
+
LOG_BUFFER_INIT(filter_state.buf);
ASSERT(!((*rte)->flags & REF_COW));
@@ -363,10 +370,11 @@ enum filter_return
f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres)
{
filter_state = (struct filter_state) {
- .stack = &filter_stack,
.pool = tmp_pool,
};
+ f_stack_init(filter_state);
+
LOG_BUFFER_INIT(filter_state.buf);
enum filter_return fret = interpret(&filter_state, expr, pres);
@@ -383,10 +391,11 @@ f_eval_int(const struct f_line *expr)
{
/* Called independently in parse-time to eval expressions */
filter_state = (struct filter_state) {
- .stack = &filter_stack,
.pool = cfg_mem,
};
+ f_stack_init(filter_state);
+
struct f_val val;
LOG_BUFFER_INIT(filter_state.buf);
diff --git a/filter/filter_test.c b/filter/filter_test.c
index 7e4af092..e8e8b747 100644
--- a/filter/filter_test.c
+++ b/filter/filter_test.c
@@ -46,9 +46,7 @@ run_function(const void *arg)
if (t->cmp)
return t->result == f_same(t->fn, t->cmp);
- linpool *tmp = lp_new_default(&root_pool);
- enum filter_return fret = f_eval(t->fn, tmp, NULL);
- rfree(tmp);
+ enum filter_return fret = f_eval(t->fn, tmp_linpool, NULL);
return (fret < F_REJECT);
}
diff --git a/filter/test.conf b/filter/test.conf
index 484628e5..2a5a2d98 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -398,7 +398,6 @@ bt_test_suite(t_ip_set, "Testing sets of ip address");
function t_enum()
{
- bt_assert(format(RTS_DUMMY) = "(enum 30)0");
bt_assert(format(RTS_STATIC) = "(enum 30)1");
bt_assert(format(NET_IP4) = "(enum 36)1");
bt_assert(format(NET_VPN6) = "(enum 36)4");
diff --git a/filter/tree_test.c b/filter/tree_test.c
index 6472d17e..05702f81 100644
--- a/filter/tree_test.c
+++ b/filter/tree_test.c
@@ -19,10 +19,7 @@ static void
start_conf_env(void)
{
bt_bird_init();
-
- pool *p = rp_new(&root_pool, "helper_pool");
- linpool *l = lp_new_default(p);
- cfg_mem = l;
+ cfg_mem = tmp_linpool;
}
static struct f_tree *
diff --git a/filter/trie_test.c b/filter/trie_test.c
index cae86995..dc791280 100644
--- a/filter/trie_test.c
+++ b/filter/trie_test.c
@@ -249,14 +249,14 @@ get_outer_net(net_addr *net, const struct f_prefix *src)
}
static list *
-make_random_prefix_list(linpool *lp, int num, int v6, int tight)
+make_random_prefix_list(int num, int v6, int tight)
{
- list *prefixes = lp_allocz(lp, sizeof(struct f_prefix_node));
+ list *prefixes = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
init_list(prefixes);
for (int i = 0; i < num; i++)
{
- struct f_prefix_node *px = lp_allocz(lp, sizeof(struct f_prefix_node));
+ struct f_prefix_node *px = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
get_random_prefix(&px->prefix, v6, tight);
add_tail(prefixes, &px->n);
@@ -269,9 +269,9 @@ make_random_prefix_list(linpool *lp, int num, int v6, int tight)
}
static struct f_trie *
-make_trie_from_prefix_list(linpool *lp, list *prefixes)
+make_trie_from_prefix_list(list *prefixes)
{
- struct f_trie *trie = f_new_trie(lp, 0);
+ struct f_trie *trie = f_new_trie(tmp_linpool, 0);
struct f_prefix_node *n;
WALK_LIST(n, *prefixes)
@@ -286,7 +286,7 @@ make_trie_from_prefix_list(linpool *lp, list *prefixes)
* Arg @plus means prefix should include all longer ones.
*/
static list *
-read_prefix_list(linpool *lp, FILE *f, int v6, int plus)
+read_prefix_list(FILE *f, int v6, int plus)
{
ASSERT(!v6);
@@ -294,7 +294,7 @@ read_prefix_list(linpool *lp, FILE *f, int v6, int plus)
char s[32];
int n;
- list *pxlist = lp_allocz(lp, sizeof(struct f_prefix_node));
+ list *pxlist = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
init_list(pxlist);
errno = 0;
@@ -308,7 +308,7 @@ read_prefix_list(linpool *lp, FILE *f, int v6, int plus)
if (n != 5)
bt_abort_msg("Invalid content of trie_data");
- struct f_prefix_node *px = lp_allocz(lp, sizeof(struct f_prefix_node));
+ struct f_prefix_node *px = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
net_fill_ip4(&px->prefix.net, ip4_build(a0, a1, a2, a3), pl);
px->prefix.lo = pl;
px->prefix.hi = plus ? IP4_MAX_PREFIX_LENGTH : pl;
@@ -331,7 +331,6 @@ read_prefix_list(linpool *lp, FILE *f, int v6, int plus)
*/
static int
read_prefix_file(const char *filename, int plus,
- linpool *lp0, linpool *lp1,
list *data[], struct f_trie *trie[])
{
FILE *f = fopen(filename, "r");
@@ -339,10 +338,10 @@ read_prefix_file(const char *filename, int plus,
int n = 0;
list *pxlist;
- while (pxlist = read_prefix_list(lp0, f, 0, plus))
+ while (pxlist = read_prefix_list(f, 0, plus))
{
data[n] = pxlist;
- trie[n] = make_trie_from_prefix_list(lp1, pxlist);
+ trie[n] = make_trie_from_prefix_list(pxlist);
bt_debug("NEXT\n");
n++;
}
@@ -437,11 +436,10 @@ t_match_random_net(void)
bt_config_parse(BT_CONFIG_SIMPLE);
int v6 = 0;
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM; round++)
{
- list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
- struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ list *prefixes = make_random_prefix_list(PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(prefixes);
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
{
@@ -451,7 +449,7 @@ t_match_random_net(void)
}
v6 = !v6;
- lp_flush(lp);
+ tmp_flush();
}
bt_bird_cleanup();
@@ -465,11 +463,10 @@ t_match_inner_net(void)
bt_config_parse(BT_CONFIG_SIMPLE);
int v6 = 0;
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM; round++)
{
- list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
- struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ list *prefixes = make_random_prefix_list(PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(prefixes);
struct f_prefix_node *n = HEAD(*prefixes);
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
@@ -482,7 +479,7 @@ t_match_inner_net(void)
}
v6 = !v6;
- lp_flush(lp);
+ tmp_flush();
}
bt_bird_cleanup();
@@ -496,11 +493,10 @@ t_match_outer_net(void)
bt_config_parse(BT_CONFIG_SIMPLE);
int v6 = 0;
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM; round++)
{
- list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
- struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ list *prefixes = make_random_prefix_list(PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(prefixes);
struct f_prefix_node *n = HEAD(*prefixes);
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
@@ -513,7 +509,7 @@ t_match_outer_net(void)
}
v6 = !v6;
- lp_flush(lp);
+ tmp_flush();
}
v6 = !v6;
@@ -531,24 +527,22 @@ static int
benchmark_trie_dataset(const char *filename, int plus)
{
int n = 0;
- linpool *lp0 = lp_new_default(&root_pool);
- linpool *lp1 = lp_new_default(&root_pool);
list *data[TRIE_BUFFER_SIZE];
struct f_trie *trie[TRIE_BUFFER_SIZE];
net_addr *nets;
bt_reset_suite_case_timer();
bt_log_suite_case_result(1, "Reading %s", filename, n);
- n = read_prefix_file(filename, plus, lp0, lp1, data, trie);
+ n = read_prefix_file(filename, plus, data, trie);
bt_log_suite_case_result(1, "Read prefix data, %d lists, ", n);
- size_t trie_size = rmemsize(lp1).effective * 1000 / (1024*1024);
+ size_t trie_size = rmemsize(tmp_linpool).effective * 1000 / (1024*1024);
bt_log_suite_case_result(1, "Trie size %u.%03u MB",
(uint) (trie_size / 1000), (uint) (trie_size % 1000));
int t = PREFIX_BENCH_NUM / n;
int tb = MIN(t, TEST_BUFFER_SIZE);
- nets = lp_alloc(lp0, tb * sizeof(net_addr));
+ nets = tmp_alloc(tb * sizeof(net_addr));
if (!plus)
select_random_prefix_subset(data, nets, n, tb);
@@ -573,9 +567,7 @@ benchmark_trie_dataset(const char *filename, int plus)
bt_log_suite_case_result(1, "Matching done, %d / %d matches", match, t * n);
- rfree(lp0);
- rfree(lp1);
-
+ tmp_flush();
return 1;
}
@@ -621,12 +613,11 @@ t_trie_same(void)
bt_config_parse(BT_CONFIG_SIMPLE);
int v6 = 0;
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM*4; round++)
{
- list *prefixes = make_random_prefix_list(lp, 100 * PREFIXES_NUM, v6, 0);
- struct f_trie *trie1 = f_new_trie(lp, 0);
- struct f_trie *trie2 = f_new_trie(lp, 0);
+ list *prefixes = make_random_prefix_list(100 * PREFIXES_NUM, v6, 0);
+ struct f_trie *trie1 = f_new_trie(tmp_linpool, 0);
+ struct f_trie *trie2 = f_new_trie(tmp_linpool, 0);
struct f_prefix_node *n;
WALK_LIST(n, *prefixes)
@@ -638,7 +629,7 @@ t_trie_same(void)
bt_assert(trie_same(trie1, trie2));
v6 = !v6;
- lp_flush(lp);
+ tmp_flush();
}
bt_bird_cleanup();
@@ -664,15 +655,14 @@ t_trie_walk(void)
bt_bird_init();
bt_config_parse(BT_CONFIG_SIMPLE);
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM*8; round++)
{
int level = round / TESTS_NUM;
int v6 = level % 2;
int num = PREFIXES_NUM * (int[]){1, 10, 100, 1000}[level / 2];
int pos = 0, end = 0;
- list *prefixes = make_random_prefix_list(lp, num, v6, 1);
- struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ list *prefixes = make_random_prefix_list(num, v6, 1);
+ struct f_trie *trie = make_trie_from_prefix_list(prefixes);
struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix));
struct f_prefix_node *n;
@@ -770,7 +760,7 @@ t_trie_walk(void)
bt_assert((pos == num) || !net_in_netX(&pxset[pos].net, &from.net));
bt_debug("Subnet walk done for %s (found %d nets)\n", buf0, pos - p0);
- lp_flush(lp);
+ tmp_flush();
}
bt_bird_cleanup();
@@ -815,7 +805,6 @@ t_trie_walk_to_root(void)
bt_bird_init();
bt_config_parse(BT_CONFIG_SIMPLE);
- linpool *lp = lp_new_default(&root_pool);
for (int round = 0; round < TESTS_NUM * 4; round++)
{
int level = round / TESTS_NUM;
@@ -824,8 +813,8 @@ t_trie_walk_to_root(void)
int pos = 0;
int st = 0, sn = 0, sm = 0;
- list *prefixes = make_random_prefix_list(lp, num, v6, 1);
- struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ list *prefixes = make_random_prefix_list(num, v6, 1);
+ struct f_trie *trie = make_trie_from_prefix_list(prefixes);
struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix));
struct f_prefix_node *pxn;
@@ -884,7 +873,7 @@ t_trie_walk_to_root(void)
bt_debug("Success in %d / %d, sum %d, max %d\n", sn, i, st, sm);
- lp_flush(lp);
+ tmp_flush();
}
bt_bird_cleanup();
diff --git a/lib/bitmap_test.c b/lib/bitmap_test.c
index 0595a4d0..07860c94 100644
--- a/lib/bitmap_test.c
+++ b/lib/bitmap_test.c
@@ -24,7 +24,6 @@ t_bmap_set_clear_random(void)
{
struct bmap b;
- resource_init();
bmap_init(&b, &root_pool, 1024);
char expected[MAX_NUM] = {};
@@ -60,7 +59,6 @@ t_hmap_set_clear_random(void)
{
struct hmap b;
- resource_init();
hmap_init(&b, &root_pool, 1024);
char expected[MAX_NUM] = {};
@@ -119,7 +117,6 @@ t_hmap_set_clear_fill(void)
{
struct hmap b;
- resource_init();
hmap_init(&b, &root_pool, 1024);
char expected[MAX_NUM] = {};
diff --git a/lib/buffer_test.c b/lib/buffer_test.c
index 5b7de330..0629e901 100644
--- a/lib/buffer_test.c
+++ b/lib/buffer_test.c
@@ -41,7 +41,6 @@ fill_expected_array(void)
static void
init_buffer(void)
{
- resource_init();
buffer_pool = &root_pool;
BUFFER_INIT(buf, buffer_pool, MAX_NUM);
}
diff --git a/lib/event.c b/lib/event.c
index 273447e0..33dc00b0 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -157,6 +157,7 @@ ev_run_list(event_list *l)
io_log_event(e->hook, e->data);
ev_run(e);
+ tmp_flush();
}
return !EMPTY_LIST(*l);
@@ -184,6 +185,7 @@ ev_run_list_limited(event_list *l, uint limit)
io_log_event(e->hook, e->data);
ev_run(e);
+ tmp_flush();
limit--;
}
diff --git a/lib/event_test.c b/lib/event_test.c
index e1215bba..e1fbea8f 100644
--- a/lib/event_test.c
+++ b/lib/event_test.c
@@ -53,7 +53,6 @@ t_ev_run_list(void)
{
int i;
- resource_init();
olock_init();
timer_init();
io_init();
diff --git a/lib/flowspec_test.c b/lib/flowspec_test.c
index ed4afe51..03649b99 100644
--- a/lib/flowspec_test.c
+++ b/lib/flowspec_test.c
@@ -446,10 +446,7 @@ t_validation6(void)
static int
t_builder4(void)
{
- resource_init();
-
struct flow_builder *fb = flow_builder_init(&root_pool);
- linpool *lp = lp_new_default(&root_pool);
/* Expectation */
@@ -492,7 +489,7 @@ t_builder4(void)
flow_builder_set_type(fb, FLOW_TYPE_TCP_FLAGS);
flow_builder_add_op_val(fb, 0, 0x55);
- net_addr_flow4 *res = flow_builder4_finalize(fb, lp);
+ net_addr_flow4 *res = flow_builder4_finalize(fb, tmp_linpool);
bt_assert(memcmp(res, expect, expect->length) == 0);
@@ -529,8 +526,6 @@ t_builder6(void)
{
net_addr_ip6 ip;
- resource_init();
- linpool *lp = lp_new_default(&root_pool);
struct flow_builder *fb = flow_builder_init(&root_pool);
fb->ipv6 = 1;
@@ -574,7 +569,7 @@ t_builder6(void)
flow_builder_set_type(fb, FLOW_TYPE_LABEL);
flow_builder_add_op_val(fb, 0, 0x55);
- net_addr_flow6 *res = flow_builder6_finalize(fb, lp);
+ net_addr_flow6 *res = flow_builder6_finalize(fb, tmp_linpool);
bt_assert(memcmp(res, expect, expect->length) == 0);
/* Reverse order */
@@ -601,7 +596,7 @@ t_builder6(void)
flow_builder_set_type(fb, FLOW_TYPE_DST_PREFIX);
flow_builder6_add_pfx(fb, &ip, 61);
- res = flow_builder6_finalize(fb, lp);
+ res = flow_builder6_finalize(fb, tmp_linpool);
bt_assert(memcmp(res, expect, expect->length) == 0);
return 1;
diff --git a/lib/hash.h b/lib/hash.h
index ea4ca6dd..8febb33f 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -215,6 +215,12 @@ mem_hash_mix(u64 *h, const void *p, uint s)
*h = *h * multiplier + pp[i];
}
+static inline void
+mem_hash_mix_num(u64 *h, u64 val)
+{
+ mem_hash_mix(h, &val, sizeof(val));
+}
+
static inline uint
mem_hash_value(u64 *h)
{
diff --git a/lib/hash_test.c b/lib/hash_test.c
index 59beb7c0..4bce7017 100644
--- a/lib/hash_test.c
+++ b/lib/hash_test.c
@@ -61,7 +61,6 @@ dump_nodes(void)
static void
init_hash_(uint order)
{
- resource_init();
my_pool = rp_new(&root_pool, "Test pool");
HASH_INIT(hash, my_pool, order);
diff --git a/lib/lists.h b/lib/lists.h
index 479f4ed1..7e6d5467 100644
--- a/lib/lists.h
+++ b/lib/lists.h
@@ -42,6 +42,7 @@ typedef union list { /* In fact two overlayed nodes */
};
} list;
+#define STATIC_LIST_INIT(name) name = { .head = &name.tail_node, .tail = &name.head_node, .null = NULL }
#define NODE (node *)
#define HEAD(list) ((void *)((list).head))
diff --git a/lib/mempool.c b/lib/mempool.c
index 90d7c774..c75f1f5b 100644
--- a/lib/mempool.c
+++ b/lib/mempool.c
@@ -39,9 +39,11 @@ struct linpool {
byte *ptr, *end;
struct lp_chunk *first, *current; /* Normal (reusable) chunks */
struct lp_chunk *first_large; /* Large chunks */
- uint chunk_size, threshold, total, total_large;
+ uint chunk_size, threshold, total:31, use_pages:1, total_large;
};
+_Thread_local linpool *tmp_linpool;
+
static void lp_free(resource *);
static void lp_dump(resource *);
static resource *lp_lookup(resource *, unsigned long);
@@ -69,6 +71,12 @@ linpool
*lp_new(pool *p, uint blk)
{
linpool *m = ralloc(p, &lp_class);
+ if (!blk)
+ {
+ m->use_pages = 1;
+ blk = page_size - lp_chunk_size;
+ }
+
m->chunk_size = blk;
m->threshold = 3*blk/4;
return m;
@@ -121,7 +129,11 @@ lp_alloc(linpool *m, uint size)
else
{
/* Need to allocate a new chunk */
- c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
+ if (m->use_pages)
+ c = alloc_page();
+ else
+ c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
+
m->total += m->chunk_size;
c->next = NULL;
c->size = m->chunk_size;
@@ -258,7 +270,10 @@ lp_free(resource *r)
for(d=m->first; d; d = c)
{
c = d->next;
- xfree(d);
+ if (m->use_pages)
+ free_page(d);
+ else
+ xfree(d);
}
for(d=m->first_large; d; d = c)
{
@@ -291,19 +306,24 @@ static struct resmem
lp_memsize(resource *r)
{
linpool *m = (linpool *) r;
- struct lp_chunk *c;
- int cnt = 0;
+ struct resmem sz = {
+ .overhead = sizeof(struct linpool) + ALLOC_OVERHEAD,
+ };
- for(c=m->first; c; c=c->next)
- cnt++;
- for(c=m->first_large; c; c=c->next)
- cnt++;
+ for (struct lp_chunk *c = m->first_large; c; c = c->next)
+ {
+ sz.effective += c->size;
+ sz.overhead += lp_chunk_size + ALLOC_OVERHEAD;
+ }
- return (struct resmem) {
- .effective = m->total + m->total_large,
- .overhead = ALLOC_OVERHEAD + sizeof(struct linpool) +
- cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)),
- };
+ uint regular = 0;
+ for (struct lp_chunk *c = m->first; c; c = c->next)
+ regular++;
+
+ sz.effective += m->chunk_size * regular;
+ sz.overhead += (lp_chunk_size + ALLOC_OVERHEAD) * regular;
+
+ return sz;
}
diff --git a/lib/resource.c b/lib/resource.c
index 5d4c7780..a179afe3 100644
--- a/lib/resource.c
+++ b/lib/resource.c
@@ -270,9 +270,12 @@ rlookup(unsigned long a)
void
resource_init(void)
{
+ resource_sys_init();
+
root_pool.r.class = &pool_class;
root_pool.name = "Root";
init_list(&root_pool.inside);
+ tmp_init(&root_pool);
}
/**
diff --git a/lib/resource.h b/lib/resource.h
index 9ec41ed8..313b01dc 100644
--- a/lib/resource.h
+++ b/lib/resource.h
@@ -79,10 +79,19 @@ void lp_flush(linpool *); /* Free everything, but leave linpool */
void lp_save(linpool *m, lp_state *p); /* Save state */
void lp_restore(linpool *m, lp_state *p); /* Restore state */
+extern _Thread_local linpool *tmp_linpool; /* Temporary linpool autoflushed regularily */
+
+#define tmp_alloc(sz) lp_alloc(tmp_linpool, sz)
+#define tmp_allocu(sz) lp_allocu(tmp_linpool, sz)
+#define tmp_allocz(sz) lp_allocz(tmp_linpool, sz)
+
+#define tmp_init(p) tmp_linpool = lp_new_default(p)
+#define tmp_flush() lp_flush(tmp_linpool)
+
extern const int lp_chunk_size;
#define LP_GAS 1024
#define LP_GOOD_SIZE(x) (((x + LP_GAS - 1) & (~(LP_GAS - 1))) - lp_chunk_size)
-#define lp_new_default(p) lp_new(p, LP_GOOD_SIZE(LP_GAS*4))
+#define lp_new_default(p) lp_new(p, 0)
/* Slabs */
@@ -101,10 +110,11 @@ void sl_free(slab *, void *);
void buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size);
/* Allocator of whole pages; for use in slabs and other high-level allocators. */
-u64 get_page_size(void);
+extern long page_size;
void *alloc_page(void);
void free_page(void *);
-extern uint pages_kept;
+
+void resource_sys_init(void);
#ifdef HAVE_LIBDMALLOC
/*
diff --git a/lib/slab.c b/lib/slab.c
index 1d844bab..9be9844d 100644
--- a/lib/slab.c
+++ b/lib/slab.c
@@ -180,7 +180,7 @@ struct sl_alignment { /* Magic structure for testing of alignment */
int x[0];
};
-#define SL_GET_HEAD(x) ((struct sl_head *) (((uintptr_t) (x)) & ~(get_page_size()-1)))
+#define SL_GET_HEAD(x) ((struct sl_head *) (((uintptr_t) (x)) & ~(page_size-1)))
/**
* sl_new - create a new Slab
@@ -202,7 +202,6 @@ sl_new(pool *p, uint size)
s->obj_size = size;
s->head_size = sizeof(struct sl_head);
- u64 page_size = get_page_size();
do {
s->objs_per_slab = (page_size - s->head_size) / size;
@@ -272,6 +271,9 @@ no_partial:
goto okay;
}
h = alloc_page();
+#ifdef POISON
+ memset(h, 0xba, page_size);
+#endif
ASSERT_DIE(SL_GET_HEAD(h) == h);
memset(h, 0, s->head_size);
add_head(&s->partial_heads, &h->n);
@@ -327,7 +329,12 @@ sl_free(slab *s, void *oo)
{
rem_node(&h->n);
if (s->num_empty_heads >= MAX_EMPTY_HEADS)
+ {
+#ifdef POISON
+ memset(h, 0xde, page_size);
+#endif
free_page(h);
+ }
else
{
add_head(&s->empty_heads, &h->n);
@@ -391,7 +398,7 @@ slab_memsize(resource *r)
return (struct resmem) {
.effective = eff,
- .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + heads * get_page_size() - eff,
+ .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + heads * page_size - eff,
};
}
@@ -402,10 +409,10 @@ slab_lookup(resource *r, unsigned long a)
struct sl_head *h;
WALK_LIST(h, s->partial_heads)
- if ((unsigned long) h < a && (unsigned long) h + get_page_size() < a)
+ if ((unsigned long) h < a && (unsigned long) h + page_size < a)
return r;
WALK_LIST(h, s->full_heads)
- if ((unsigned long) h < a && (unsigned long) h + get_page_size() < a)
+ if ((unsigned long) h < a && (unsigned long) h + page_size < a)
return r;
return NULL;
}
diff --git a/lib/timer.c b/lib/timer.c
index 381163d0..c47e0bbc 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -233,6 +233,7 @@ timers_fire(struct timeloop *loop)
io_log_event(t->hook, t->data);
t->hook(t);
+ tmp_flush();
}
}
diff --git a/nest/a-path_test.c b/nest/a-path_test.c
index 9ed0a786..e007a450 100644
--- a/nest/a-path_test.c
+++ b/nest/a-path_test.c
@@ -23,8 +23,6 @@
static int
t_as_path_match(void)
{
- resource_init();
-
int round;
for (round = 0; round < TESTS_NUM; round++)
{
@@ -32,14 +30,13 @@ t_as_path_match(void)
struct adata *as_path = &empty_as_path;
u32 first_prepended, last_prepended;
first_prepended = last_prepended = 0;
- struct linpool *lp = lp_new_default(&root_pool);
struct f_path_mask *mask = alloca(sizeof(struct f_path_mask) + AS_PATH_LENGTH * sizeof(struct f_path_mask_item));
mask->len = AS_PATH_LENGTH;
for (int i = AS_PATH_LENGTH - 1; i >= 0; i--)
{
u32 val = bt_random();
- as_path = as_path_prepend(lp, as_path, val);
+ as_path = as_path_prepend(tmp_linpool, as_path, val);
bt_debug("Prepending ASN: %10u \n", val);
if (i == 0)
@@ -61,7 +58,7 @@ t_as_path_match(void)
bt_assert(as_path_get_last(as_path, &asn));
bt_assert_msg(asn == first_prepended, "as_path_get_last() should return the first prepended ASN");
- rfree(lp);
+ tmp_flush();
}
return 1;
@@ -70,16 +67,13 @@ t_as_path_match(void)
static int
t_path_format(void)
{
- resource_init();
-
struct adata empty_as_path = {};
struct adata *as_path = &empty_as_path;
- struct linpool *lp = lp_new_default(&root_pool);
uint i;
for (i = 4294967285; i <= 4294967294; i++)
{
- as_path = as_path_prepend(lp, as_path, i);
+ as_path = as_path_prepend(tmp_linpool, as_path, i);
bt_debug("Prepending ASN: %10u \n", i);
}
@@ -97,7 +91,7 @@ t_path_format(void)
as_path_format(as_path, buf2, SMALL_BUFFER_SIZE);
bt_assert_msg(strcmp(buf2, "4294967294 42...") == 0, "Small Buffer(%zu): '%s'", strlen(buf2), buf2);
- rfree(lp);
+ tmp_flush();
return 1;
}
@@ -116,11 +110,8 @@ count_asn_in_array(const u32 *array, u32 asn)
static int
t_path_include(void)
{
- resource_init();
-
struct adata empty_as_path = {};
struct adata *as_path = &empty_as_path;
- struct linpool *lp = lp_new_default(&root_pool);
u32 as_nums[AS_PATH_LENGTH] = {};
int i;
@@ -128,7 +119,7 @@ t_path_include(void)
{
u32 val = bt_random();
as_nums[i] = val;
- as_path = as_path_prepend(lp, as_path, val);
+ as_path = as_path_prepend(tmp_linpool, as_path, val);
}
for (i = 0; i < AS_PATH_LENGTH; i++)
@@ -136,8 +127,8 @@ t_path_include(void)
int counts_of_contains = count_asn_in_array(as_nums, as_nums[i]);
bt_assert_msg(as_path_contains(as_path, as_nums[i], counts_of_contains), "AS Path should contains %d-times number %d", counts_of_contains, as_nums[i]);
- bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 0) != NULL);
- bt_assert(as_path_filter(lp, as_path, NULL, as_nums[i], 1) != NULL);
+ bt_assert(as_path_filter(tmp_linpool, as_path, NULL, as_nums[i], 0) != NULL);
+ bt_assert(as_path_filter(tmp_linpool, as_path, NULL, as_nums[i], 1) != NULL);
}
for (i = 0; i < 10000; i++)
@@ -152,7 +143,7 @@ t_path_include(void)
bt_assert_msg(result == 0, "As path should not contain the number %u", test_val);
}
- rfree(lp);
+ tmp_flush();
return 1;
}
@@ -161,16 +152,13 @@ t_path_include(void)
static int
t_as_path_converting(void)
{
- resource_init();
-
struct adata empty_as_path = {};
struct adata *as_path = &empty_as_path;
- struct linpool *lp = lp_new_default(&root_pool);
#define AS_PATH_LENGTH_FOR_CONVERTING_TEST 10
int i;
for (i = 0; i < AS_PATH_LENGTH_FOR_CONVERTING_TEST; i++)
- as_path = as_path_prepend(lp, as_path, i);
+ as_path = as_path_prepend(tmp_linpool, as_path, i);
bt_debug("data length: %u \n", as_path->length);
diff --git a/nest/a-set_test.c b/nest/a-set_test.c
index 96b6a727..904e6764 100644
--- a/nest/a-set_test.c
+++ b/nest/a-set_test.c
@@ -25,8 +25,6 @@ static byte buf[BUFFER_SIZE] = {};
#define SET_SIZE_FOR_FORMAT_OUTPUT 10
-struct linpool *lp;
-
enum set_type
{
SET_TYPE_INT,
@@ -38,24 +36,23 @@ generate_set_sequence(enum set_type type, int len)
{
struct adata empty_as_path = {};
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
- lp = lp_new_default(&root_pool);
int i;
for (i = 0; i < len; i++)
{
if (type == SET_TYPE_INT)
{
- set_sequence = int_set_add(lp, set_sequence, i);
- set_sequence_same = int_set_add(lp, set_sequence_same, i);
- set_sequence_higher = int_set_add(lp, set_sequence_higher, i + SET_SIZE);
- set_random = int_set_add(lp, set_random, bt_random());
+ set_sequence = int_set_add(tmp_linpool, set_sequence, i);
+ set_sequence_same = int_set_add(tmp_linpool, set_sequence_same, i);
+ set_sequence_higher = int_set_add(tmp_linpool, set_sequence_higher, i + SET_SIZE);
+ set_random = int_set_add(tmp_linpool, set_random, bt_random());
}
else if (type == SET_TYPE_EC)
{
- set_sequence = ec_set_add(lp, set_sequence, i);
- set_sequence_same = ec_set_add(lp, set_sequence_same, i);
- set_sequence_higher = ec_set_add(lp, set_sequence_higher, i + SET_SIZE);
- set_random = ec_set_add(lp, set_random, (bt_random() << 32 | bt_random()));
+ set_sequence = ec_set_add(tmp_linpool, set_sequence, i);
+ set_sequence_same = ec_set_add(tmp_linpool, set_sequence_same, i);
+ set_sequence_higher = ec_set_add(tmp_linpool, set_sequence_higher, i + SET_SIZE);
+ set_random = ec_set_add(tmp_linpool, set_random, (bt_random() << 32 | bt_random()));
}
else
bt_abort_msg("This should be unreachable");
@@ -71,7 +68,6 @@ t_set_int_contains(void)
{
int i;
- resource_init();
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
bt_assert(int_set_get_size(set_sequence) == SET_SIZE);
@@ -85,33 +81,29 @@ t_set_int_contains(void)
for (i = 0; i < SET_SIZE; i++)
bt_assert_msg(data[i] == i, "(data[i] = %d) == i = %d)", data[i], i);
- rfree(lp);
return 1;
}
static int
t_set_int_union(void)
{
- resource_init();
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
const struct adata *set_union;
- set_union = int_set_union(lp, set_sequence, set_sequence_same);
+ set_union = int_set_union(tmp_linpool, set_sequence, set_sequence_same);
bt_assert(int_set_get_size(set_union) == SET_SIZE);
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
- set_union = int_set_union(lp, set_sequence, set_sequence_higher);
+ set_union = int_set_union(tmp_linpool, set_sequence, set_sequence_higher);
bt_assert_msg(int_set_get_size(set_union) == SET_SIZE*2, "int_set_get_size(set_union) %d, SET_SIZE*2 %d", int_set_get_size(set_union), SET_SIZE*2);
bt_assert(int_set_format(set_union, 0, 2, buf, BUFFER_SIZE) == 0);
- rfree(lp);
return 1;
}
static int
t_set_int_format(void)
{
- resource_init();
generate_set_sequence(SET_TYPE_INT, SET_SIZE_FOR_FORMAT_OUTPUT);
bt_assert(int_set_format(set_sequence, 0, 0, buf, BUFFER_SIZE) == 0);
@@ -125,21 +117,19 @@ t_set_int_format(void)
bt_assert(int_set_format(set_sequence, 1, 0, buf, BUFFER_SIZE) == 0);
bt_assert(strcmp(buf, "(0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9)") == 0);
- rfree(lp);
return 1;
}
static int
t_set_int_delete(void)
{
- resource_init();
generate_set_sequence(SET_TYPE_INT, SET_SIZE);
const struct adata *deleting_sequence = set_sequence;
u32 i;
for (i = 0; i < SET_SIZE; i++)
{
- deleting_sequence = int_set_del(lp, deleting_sequence, i);
+ deleting_sequence = int_set_del(tmp_linpool, deleting_sequence, i);
bt_assert_msg(int_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
"int_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
int_set_get_size(deleting_sequence),
@@ -160,7 +150,6 @@ t_set_ec_contains(void)
{
u32 i;
- resource_init();
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
bt_assert(ec_set_get_size(set_sequence) == SET_SIZE);
@@ -174,62 +163,54 @@ t_set_ec_contains(void)
// for (i = 0; i < SET_SIZE; i++)
// bt_assert_msg(data[i] == (SET_SIZE-1-i), "(data[i] = %d) == ((SET_SIZE-1-i) = %d)", data[i], SET_SIZE-1-i);
- rfree(lp);
return 1;
}
static int
t_set_ec_union(void)
{
- resource_init();
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
const struct adata *set_union;
- set_union = ec_set_union(lp, set_sequence, set_sequence_same);
+ set_union = ec_set_union(tmp_linpool, set_sequence, set_sequence_same);
bt_assert(ec_set_get_size(set_union) == SET_SIZE);
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
- set_union = ec_set_union(lp, set_sequence, set_sequence_higher);
+ set_union = ec_set_union(tmp_linpool, set_sequence, set_sequence_higher);
bt_assert_msg(ec_set_get_size(set_union) == SET_SIZE*2, "ec_set_get_size(set_union) %d, SET_SIZE*2 %d", ec_set_get_size(set_union), SET_SIZE*2);
bt_assert(ec_set_format(set_union, 0, buf, BUFFER_SIZE) == 0);
- rfree(lp);
return 1;
}
static int
t_set_ec_format(void)
{
- resource_init();
-
const struct adata empty_as_path = {};
set_sequence = set_sequence_same = set_sequence_higher = set_random = &empty_as_path;
- lp = lp_new_default(&root_pool);
u64 i = 0;
- set_sequence = ec_set_add(lp, set_sequence, i);
+ set_sequence = ec_set_add(tmp_linpool, set_sequence, i);
for (i = 1; i < SET_SIZE_FOR_FORMAT_OUTPUT; i++)
- set_sequence = ec_set_add(lp, set_sequence, i + ((i%2) ? ((u64)EC_RO << 48) : ((u64)EC_RT << 48)));
+ set_sequence = ec_set_add(tmp_linpool, set_sequence, i + ((i%2) ? ((u64)EC_RO << 48) : ((u64)EC_RT << 48)));
bt_assert(ec_set_format(set_sequence, 0, buf, BUFFER_SIZE) == 0);
bt_assert_msg(strcmp(buf, "(unknown 0x0, 0, 0) (ro, 0, 1) (rt, 0, 2) (ro, 0, 3) (rt, 0, 4) (ro, 0, 5) (rt, 0, 6) (ro, 0, 7) (rt, 0, 8) (ro, 0, 9)") == 0,
"ec_set_format() returns '%s'", buf);
- rfree(lp);
return 1;
}
static int
t_set_ec_delete(void)
{
- resource_init();
generate_set_sequence(SET_TYPE_EC, SET_SIZE);
const struct adata *deleting_sequence = set_sequence;
u32 i;
for (i = 0; i < SET_SIZE; i++)
{
- deleting_sequence = ec_set_del(lp, deleting_sequence, i);
+ deleting_sequence = ec_set_del(tmp_linpool, deleting_sequence, i);
bt_assert_msg(ec_set_get_size(deleting_sequence) == (int) (SET_SIZE-1-i),
"ec_set_get_size(deleting_sequence) %d == SET_SIZE-1-i %d",
ec_set_get_size(deleting_sequence), SET_SIZE-1-i);
diff --git a/nest/cmds.c b/nest/cmds.c
index 1a16f9c7..8481bf96 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -108,6 +108,7 @@ print_size(char *dsc, struct resmem vals)
extern pool *rt_table_pool;
extern pool *rta_pool;
+extern uint *pages_kept;
void
cmd_show_memory(void)
@@ -119,8 +120,8 @@ cmd_show_memory(void)
print_size("Protocols:", rmemsize(proto_pool));
struct resmem total = rmemsize(&root_pool);
#ifdef HAVE_MMAP
- print_size("Standby memory:", (struct resmem) { .overhead = get_page_size() * pages_kept });
- total.overhead += get_page_size() * pages_kept;
+ print_size("Standby memory:", (struct resmem) { .overhead = page_size * *pages_kept });
+ total.overhead += page_size * *pages_kept;
#endif
print_size("Total:", total);
cli_msg(0, "");
diff --git a/nest/config.Y b/nest/config.Y
index 72bc7930..92a80589 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -130,7 +130,7 @@ CF_KEYWORDS(SORTED, TRIE, MIN, MAX, SETTLE, TIME)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
-CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
+CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c
index bc88b4b4..716ce86c 100644
--- a/nest/proto-hooks.c
+++ b/nest/proto-hooks.c
@@ -76,16 +76,6 @@ void dump(struct proto *p)
{ DUMMY; }
/**
- * dump_attrs - dump protocol-dependent attributes
- * @e: a route entry
- *
- * This hook dumps all attributes in the &rte which belong to this
- * protocol to the debug output.
- */
-void dump_attrs(rte *e)
-{ DUMMY; }
-
-/**
* start - request instance startup
* @p: protocol instance
*
@@ -228,36 +218,6 @@ void neigh_notify(neighbor *neigh)
{ DUMMY; }
/**
- * make_tmp_attrs - convert embedded attributes to temporary ones
- * @e: route entry
- * @pool: linear pool to allocate attribute memory in
- *
- * This hook is called by the routing table functions if they need
- * to convert the protocol attributes embedded directly in the &rte
- * to temporary extended attributes in order to distribute them
- * to other protocols or to filters. make_tmp_attrs() creates
- * an &ea_list in the linear pool @pool, fills it with values of the
- * temporary attributes and returns a pointer to it.
- */
-ea_list *make_tmp_attrs(rte *e, struct linpool *pool)
-{ DUMMY; }
-
-/**
- * store_tmp_attrs - convert temporary attributes to embedded ones
- * @e: route entry
- * @attrs: temporary attributes to be converted
- *
- * This hook is an exact opposite of make_tmp_attrs() -- it takes
- * a list of extended attributes and converts them to attributes
- * embedded in the &rte corresponding to this protocol.
- *
- * You must be prepared for any of the attributes being missing
- * from the list and use default values instead.
- */
-void store_tmp_attrs(rte *e, ea_list *attrs)
-{ DUMMY; }
-
-/**
* preexport - pre-filtering decisions before route export
* @p: protocol instance the route is going to be exported to
* @e: the route in question
diff --git a/nest/proto.c b/nest/proto.c
index 31ee1fa1..7cfb1555 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -2243,8 +2243,13 @@ proto_apply_cmd_symbol(const struct symbol *s, void (* cmd)(struct proto *, uint
return;
}
- cmd(s->proto->proto, arg, 0);
- cli_msg(0, "");
+ if (s->proto->proto)
+ {
+ cmd(s->proto->proto, arg, 0);
+ cli_msg(0, "");
+ }
+ else
+ cli_msg(9002, "%s does not exist", s->name);
}
static void
diff --git a/nest/protocol.h b/nest/protocol.h
index abcc505d..e05dd7ec 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -74,7 +74,6 @@ struct protocol {
struct proto * (*init)(struct proto_config *); /* Create new instance */
int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance, returns success */
void (*dump)(struct proto *); /* Debugging dump */
- void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */
int (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
@@ -198,12 +197,11 @@ struct proto {
* ifa_notify Notify protocol about interface address changes.
* rt_notify Notify protocol about routing table updates.
* neigh_notify Notify protocol about neighbor cache events.
- * make_tmp_attrs Add attributes to rta from from private attrs stored in rte. The route and rta MUST NOT be cached.
- * store_tmp_attrs Store private attrs back to rte and undef added attributes. The route and rta MUST NOT be cached.
- * preexport Called as the first step of the route exporting process.
- * It can construct a new rte, add private attributes and
- * decide whether the route shall be exported: 1=yes, -1=no,
- * 0=process it through the export filter set by the user.
+ * preexport Called as the first step of the route exporting process.
+ * It can decide whether the route shall be exported:
+ * -1 = reject,
+ * 0 = continue to export filter
+ * 1 = accept immediately
* reload_routes Request channel to reload all its routes to the core
* (using rte_update()). Returns: 0=reload cannot be done,
* 1= reload is scheduled and will happen (asynchronously).
@@ -215,9 +213,7 @@ struct proto {
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
void (*neigh_notify)(struct neighbor *neigh);
- void (*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
- void (*store_tmp_attrs)(struct rte *rt, struct linpool *pool);
- int (*preexport)(struct proto *, struct rte **rt, struct linpool *pool);
+ int (*preexport)(struct proto *, struct rte *rt);
void (*reload_routes)(struct channel *);
void (*feed_begin)(struct channel *, int initial);
void (*feed_end)(struct channel *);
@@ -235,11 +231,11 @@ struct proto {
int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
int (*rte_better)(struct rte *, struct rte *);
- int (*rte_same)(struct rte *, struct rte *);
int (*rte_mergable)(struct rte *, struct rte *);
struct rte * (*rte_modify)(struct rte *, struct linpool *);
void (*rte_insert)(struct network *, struct rte *);
void (*rte_remove)(struct network *, struct rte *);
+ u32 (*rte_igp_metric)(struct rte *);
/* Hic sunt protocol-specific data */
};
@@ -469,7 +465,6 @@ struct channel_class {
void (*dump)(struct proto *); /* Debugging dump */
- void (*dump_attrs)(struct rte *); /* Dump protocol-dependent attributes */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
diff --git a/nest/route.h b/nest/route.h
index 7930058a..595acabd 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -255,50 +255,13 @@ struct hostentry {
typedef struct rte {
struct rte *next;
net *net; /* Network this RTE belongs to */
+ struct rte_src *src; /* Route source that created the route */
struct channel *sender; /* Channel used to send the route to the routing table */
struct rta *attrs; /* Attributes of this route */
u32 id; /* Table specific route id */
byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */
- word pref; /* Route preference */
btime lastmod; /* Last modified */
- union { /* Protocol-dependent data (metrics etc.) */
-#ifdef CONFIG_RIP
- struct {
- struct iface *from; /* Incoming iface */
- u8 metric; /* RIP metric */
- u16 tag; /* External route tag */
- } rip;
-#endif
-#ifdef CONFIG_OSPF
- struct {
- u32 metric1, metric2; /* OSPF Type 1 and Type 2 metrics */
- u32 tag; /* External route tag */
- u32 router_id; /* Router that originated this route */
- } ospf;
-#endif
-#ifdef CONFIG_BGP
- struct {
- u8 suppressed; /* Used for deterministic MED comparison */
- s8 stale; /* Route is LLGR_STALE, -1 if unknown */
- struct rtable *base_table; /* Base table for Flowspec validation */
- } bgp;
-#endif
-#ifdef CONFIG_BABEL
- struct {
- u16 seqno; /* Babel seqno */
- u16 metric; /* Babel metric */
- u64 router_id; /* Babel router id */
- } babel;
-#endif
- struct { /* Routes generated by krt sync (both temporary and inherited ones) */
- s8 src; /* Alleged route source (see krt.h) */
- u8 proto; /* Kernel source protocol ID */
- u8 seen; /* Seen during last scan */
- u8 best; /* Best route in network, propagated to core */
- u32 metric; /* Kernel metric */
- } krt;
- } u;
} rte;
#define REF_COW 1 /* Copy this rte on write */
@@ -352,7 +315,7 @@ net *net_get(rtable *tab, const net_addr *addr);
net *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
rte *rte_find(net *net, struct rte_src *src);
-rte *rte_get_temp(struct rta *);
+rte *rte_get_temp(struct rta *, struct rte_src *src);
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
@@ -366,10 +329,6 @@ void rte_free(rte *);
rte *rte_do_cow(rte *);
static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
rte *rte_cow_rta(rte *r, linpool *lp);
-void rte_init_tmp_attrs(struct rte *r, linpool *lp, uint max);
-void rte_make_tmp_attr(struct rte *r, uint id, uint type, uintptr_t val);
-void rte_make_tmp_attrs(struct rte **r, struct linpool *pool, struct rta **old_attrs);
-uintptr_t rte_store_tmp_attr(struct rte *r, uint id);
void rt_dump(rtable *);
void rt_dump_all(void);
int rt_feed_channel(struct channel *c);
@@ -378,7 +337,7 @@ int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);
-int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed);
+int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, rte **old_exported, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
static inline int rt_is_ip(rtable *tab)
@@ -487,18 +446,17 @@ typedef struct rta {
u32 uc; /* Use count */
u32 hash_key; /* Hash over important fields */
struct ea_list *eattrs; /* Extended Attribute chain */
- struct rte_src *src; /* Route source that created the route */
struct hostentry *hostentry; /* Hostentry for recursive next-hops */
ip_addr from; /* Advertising router */
u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */
- u8 source; /* Route source (RTS_...) */
- u8 scope; /* Route scope (SCOPE_... -- see ip.h) */
- u8 dest; /* Route destination type (RTD_...) */
- u8 aflags;
+ u16 cached:1; /* Are attributes cached? */
+ u16 source:7; /* Route source (RTS_...) */
+ u16 scope:4; /* Route scope (SCOPE_... -- see ip.h) */
+ u16 dest:4; /* Route destination type (RTD_...) */
+ word pref;
struct nexthop nh; /* Next hop */
} rta;
-#define RTS_DUMMY 0 /* Dummy route to be removed soon */
#define RTS_STATIC 1 /* Normal static route */
#define RTS_INHERIT 2 /* Route inherited from kernel */
#define RTS_DEVICE 3 /* Device route */
@@ -516,11 +474,6 @@ typedef struct rta {
#define RTS_PERF 15 /* Perf checker */
#define RTS_MAX 16
-#define RTC_UNICAST 0
-#define RTC_BROADCAST 1
-#define RTC_MULTICAST 2
-#define RTC_ANYCAST 3 /* IPv6 Anycast */
-
#define RTD_NONE 0 /* Undefined next hop */
#define RTD_UNICAST 1 /* Next hop is neighbor router */
#define RTD_BLACKHOLE 2 /* Silently drop packets */
@@ -528,8 +481,6 @@ typedef struct rta {
#define RTD_PROHIBIT 4 /* Administratively prohibited */
#define RTD_MAX 5
-#define RTAF_CACHED 1 /* This is a cached rta */
-
#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other
protocol-specific metric is availabe */
@@ -553,8 +504,8 @@ typedef struct eattr {
byte flags; /* Protocol-dependent flags */
byte type; /* Attribute type and several flags (EAF_...) */
union {
- u32 data;
- const struct adata *ptr; /* Attribute data elsewhere */
+ uintptr_t data;
+ const struct adata *ptr; /* Attribute data elsewhere */
} u;
} eattr;
@@ -562,7 +513,6 @@ typedef struct eattr {
#define EA_CODE(proto,id) (((proto) << 8) | (id))
#define EA_ID(ea) ((ea) & 0xff)
#define EA_PROTO(ea) ((ea) >> 8)
-#define EA_ID_FLAG(ea) (1 << EA_ID(ea))
#define EA_CUSTOM(id) ((id) | EA_CUSTOM_BIT)
#define EA_IS_CUSTOM(ea) ((ea) & EA_CUSTOM_BIT)
#define EA_CUSTOM_ID(ea) ((ea) & ~EA_CUSTOM_BIT)
@@ -585,6 +535,7 @@ const char *ea_custom_name(uint ea);
#define EAF_TYPE_AS_PATH 0x06 /* BGP AS path (encoding per RFC 1771:4.3) */
#define EAF_TYPE_BITFIELD 0x09 /* 32-bit embedded bitfield */
#define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */
+#define EAF_TYPE_PTR 0x0d /* Pointer to an object */
#define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */
#define EAF_TYPE_LC_SET 0x12 /* Set of triplets of u32's - large community list */
#define EAF_TYPE_UNDEF 0x1f /* `force undefined' entry */
@@ -623,7 +574,6 @@ typedef struct ea_list {
#define EALF_SORTED 1 /* Attributes are sorted by code */
#define EALF_BISECT 2 /* Use interval bisection for searching */
#define EALF_CACHED 4 /* Attributes belonging to cached rta */
-#define EALF_TEMP 8 /* Temporary ea_list added by make_tmp_attrs hooks */
struct rte_src *rt_find_source(struct proto *p, u32 id);
struct rte_src *rt_get_source(struct proto *p, u32 id);
@@ -639,7 +589,7 @@ struct ea_walk_state {
eattr *ea_find(ea_list *, unsigned ea);
eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
-int ea_get_int(ea_list *, unsigned ea, int def);
+uintptr_t ea_get_int(ea_list *, unsigned ea, uintptr_t def);
void ea_dump(ea_list *);
void ea_sort(ea_list *); /* Sort entries in all sub-lists */
unsigned ea_scan(ea_list *); /* How many bytes do we need for merged ea_list */
@@ -718,7 +668,7 @@ void rta_init(void);
static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; }
#define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
-static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
+static inline int rta_is_cached(rta *r) { return r->cached; }
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index c630aa95..1bece201 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -61,7 +61,6 @@
const adata null_adata; /* adata of length 0 */
const char * const rta_src_names[RTS_MAX] = {
- [RTS_DUMMY] = "",
[RTS_STATIC] = "static",
[RTS_INHERIT] = "inherit",
[RTS_DEVICE] = "device",
@@ -541,8 +540,8 @@ ea_walk(struct ea_walk_state *s, uint id, uint max)
* by calling ea_find() to find the attribute, extracting its value or returning
* a provided default if no such attribute is present.
*/
-int
-ea_get_int(ea_list *e, unsigned id, int def)
+uintptr_t
+ea_get_int(ea_list *e, unsigned id, uintptr_t def)
{
eattr *a = ea_find(e, id);
if (!a)
@@ -1104,13 +1103,14 @@ rta_hash(rta *a)
u64 h;
mem_hash_init(&h);
#define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f));
- MIX(src);
+#define BMIX(f) mem_hash_mix_num(&h, a->f);
MIX(hostentry);
MIX(from);
MIX(igp_metric);
- MIX(source);
- MIX(scope);
- MIX(dest);
+ BMIX(source);
+ BMIX(scope);
+ BMIX(dest);
+ MIX(pref);
#undef MIX
return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
@@ -1119,8 +1119,7 @@ rta_hash(rta *a)
static inline int
rta_same(rta *x, rta *y)
{
- return (x->src == y->src &&
- x->source == y->source &&
+ return (x->source == y->source &&
x->scope == y->scope &&
x->dest == y->dest &&
x->igp_metric == y->igp_metric &&
@@ -1198,7 +1197,7 @@ rta_lookup(rta *o)
rta *r;
uint h;
- ASSERT(!(o->aflags & RTAF_CACHED));
+ ASSERT(!o->cached);
if (o->eattrs)
ea_normalize(o->eattrs);
@@ -1209,8 +1208,7 @@ rta_lookup(rta *o)
r = rta_copy(o);
r->hash_key = h;
- r->aflags = RTAF_CACHED;
- rt_lock_source(r->src);
+ r->cached = 1;
rt_lock_hostentry(r->hostentry);
rta_insert(r);
@@ -1223,17 +1221,16 @@ rta_lookup(rta *o)
void
rta__free(rta *a)
{
- ASSERT(rta_cache_count && (a->aflags & RTAF_CACHED));
+ ASSERT(rta_cache_count && a->cached);
rta_cache_count--;
*a->pprev = a->next;
if (a->next)
a->next->pprev = a->pprev;
rt_unlock_hostentry(a->hostentry);
- rt_unlock_source(a->src);
if (a->nh.next)
nexthop_free(a->nh.next);
ea_free(a->eattrs);
- a->aflags = 0; /* Poison the entry */
+ a->cached = 0;
sl_free(rta_slab(a), a);
}
@@ -1248,7 +1245,7 @@ rta_do_cow(rta *o, linpool *lp)
memcpy(*nhn, nho, nexthop_size(nho));
nhn = &((*nhn)->next);
}
- r->aflags = 0;
+ r->cached = 0;
r->uc = 0;
return r;
}
@@ -1262,16 +1259,16 @@ rta_do_cow(rta *o, linpool *lp)
void
rta_dump(rta *a)
{
- static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
+ static char *rts[] = { "", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
"RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
"RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
"RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
- debug("p=%s uc=%d %s %s%s h=%04x",
- a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope),
+ debug("pref=%d uc=%d %s %s%s h=%04x",
+ a->pref, a->uc, rts[a->source], ip_scope_text(a->scope),
rtd[a->dest], a->hash_key);
- if (!(a->aflags & RTAF_CACHED))
+ if (!a->cached)
debug(" !CACHED");
debug(" <-%I", a->from);
if (a->dest == RTD_UNICAST)
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 61f025ce..e2e65926 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -83,7 +83,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
struct rte_src *src = rt_get_source(P, ad->iface->index);
rta a0 = {
- .src = src,
+ .pref = c->preference,
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
@@ -91,7 +91,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
};
a = rta_lookup(&a0);
- e = rte_get_temp(a);
+ e = rte_get_temp(a, src);
e->pflags = 0;
rte_update2(c, net, e, src);
}
diff --git a/nest/rt-show.c b/nest/rt-show.c
index f8b7ba51..19877966 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -57,17 +57,17 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
if (d->verbose && !rta_is_cached(a) && a->eattrs)
ea_normalize(a->eattrs);
- get_route_info = a->src->proto->proto->get_route_info;
+ get_route_info = e->src->proto->proto->get_route_info;
if (get_route_info)
get_route_info(e, info);
else
- bsprintf(info, " (%d)", e->pref);
+ bsprintf(info, " (%d)", a->pref);
if (d->last_table != d->tab)
rt_show_table(c, d);
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
- a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
+ e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (a->dest == RTD_UNICAST)
for (nh = &(a->nh); nh; nh = nh->next)
@@ -127,7 +127,6 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
continue;
ee = e;
- rte_make_tmp_attrs(&e, c->show_pool, NULL);
/* Export channel is down, do not try to export routes to it */
if (ec && (ec->export_state == ES_DOWN))
@@ -154,7 +153,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
else if (d->export_mode)
{
struct proto *ep = ec->proto;
- int ic = ep->preexport ? ep->preexport(ep, &e, c->show_pool) : 0;
+ int ic = ep->preexport ? ep->preexport(ep, e) : 0;
if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
pass = 1;
@@ -180,7 +179,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
}
}
- if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
+ if (d->show_protocol && (d->show_protocol != e->src->proto))
goto skip;
if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT)
@@ -393,7 +392,7 @@ rt_show_get_default_tables(struct rt_show_data *d)
}
for (int i=1; i<NET_MAX; i++)
- if (config->def_tables[i])
+ if (config->def_tables[i] && config->def_tables[i]->table)
rt_show_add_table(d, config->def_tables[i]->table);
}
diff --git a/nest/rt-table.c b/nest/rt-table.c
index a10979e6..b3ca3d05 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -548,7 +548,7 @@ rte_find(net *net, struct rte_src *src)
{
rte *e = net->routes;
- while (e && e->attrs->src != src)
+ while (e && e->src != src)
e = e->next;
return e;
}
@@ -563,14 +563,14 @@ rte_find(net *net, struct rte_src *src)
* the protocol.
*/
rte *
-rte_get_temp(rta *a)
+rte_get_temp(rta *a, struct rte_src *src)
{
rte *e = sl_alloc(rte_slab);
e->attrs = a;
e->id = 0;
e->flags = 0;
- e->pref = 0;
+ rt_lock_source(e->src = src);
return e;
}
@@ -580,6 +580,8 @@ rte_do_cow(rte *r)
rte *e = sl_alloc(rte_slab);
memcpy(e, r, sizeof(rte));
+
+ rt_lock_source(e->src);
e->attrs = rta_clone(r->attrs);
e->flags = 0;
return e;
@@ -617,176 +619,29 @@ rte_cow_rta(rte *r, linpool *lp)
return r;
}
-
-/**
- * rte_init_tmp_attrs - initialize temporary ea_list for route
- * @r: route entry to be modified
- * @lp: linpool from which to allocate attributes
- * @max: maximum number of added temporary attribus
- *
- * This function is supposed to be called from make_tmp_attrs() and
- * store_tmp_attrs() hooks before rte_make_tmp_attr() / rte_store_tmp_attr()
- * functions. It allocates &ea_list with length for @max items for temporary
- * attributes and puts it on top of eattrs stack.
- */
-void
-rte_init_tmp_attrs(rte *r, linpool *lp, uint max)
-{
- struct ea_list *e = lp_alloc(lp, sizeof(struct ea_list) + max * sizeof(eattr));
-
- e->next = r->attrs->eattrs;
- e->flags = EALF_SORTED | EALF_TEMP;
- e->count = 0;
-
- r->attrs->eattrs = e;
-}
-
-/**
- * rte_make_tmp_attr - make temporary eattr from private route fields
- * @r: route entry to be modified
- * @id: attribute ID
- * @type: attribute type
- * @val: attribute value (u32 or adata ptr)
- *
- * This function is supposed to be called from make_tmp_attrs() hook for
- * each temporary attribute, after temporary &ea_list was initialized by
- * rte_init_tmp_attrs(). It checks whether temporary attribute is supposed to
- * be defined (based on route pflags) and if so then it fills &eattr field in
- * preallocated temporary &ea_list on top of route @r eattrs stack.
- *
- * Note that it may require free &eattr in temporary &ea_list, so it must not be
- * called more times than @max argument of rte_init_tmp_attrs().
- */
-void
-rte_make_tmp_attr(rte *r, uint id, uint type, uintptr_t val)
-{
- if (r->pflags & EA_ID_FLAG(id))
- {
- ea_list *e = r->attrs->eattrs;
- eattr *a = &e->attrs[e->count++];
- a->id = id;
- a->type = type;
- a->flags = 0;
-
- if (type & EAF_EMBEDDED)
- a->u.data = (u32) val;
- else
- a->u.ptr = (struct adata *) val;
- }
-}
-
-/**
- * rte_store_tmp_attr - store temporary eattr to private route fields
- * @r: route entry to be modified
- * @id: attribute ID
- *
- * This function is supposed to be called from store_tmp_attrs() hook for
- * each temporary attribute, after temporary &ea_list was initialized by
- * rte_init_tmp_attrs(). It checks whether temporary attribute is defined in
- * route @r eattrs stack, updates route pflags accordingly, undefines it by
- * filling &eattr field in preallocated temporary &ea_list on top of the eattrs
- * stack, and returns the value. Caller is supposed to store it in the
- * appropriate private field.
- *
- * Note that it may require free &eattr in temporary &ea_list, so it must not be
- * called more times than @max argument of rte_init_tmp_attrs()
- */
-uintptr_t
-rte_store_tmp_attr(rte *r, uint id)
-{
- ea_list *e = r->attrs->eattrs;
- eattr *a = ea_find(e->next, id);
-
- if (a)
- {
- e->attrs[e->count++] = (struct eattr) { .id = id, .type = EAF_TYPE_UNDEF };
- r->pflags |= EA_ID_FLAG(id);
- return (a->type & EAF_EMBEDDED) ? a->u.data : (uintptr_t) a->u.ptr;
- }
- else
- {
- r->pflags &= ~EA_ID_FLAG(id);
- return 0;
- }
-}
-
/**
- * rte_make_tmp_attrs - prepare route by adding all relevant temporary route attributes
- * @r: route entry to be modified (may be replaced if COW)
- * @lp: linpool from which to allocate attributes
- * @old_attrs: temporary ref to old &rta (may be NULL)
- *
- * This function expands privately stored protocol-dependent route attributes
- * to a uniform &eattr / &ea_list representation. It is essentially a wrapper
- * around protocol make_tmp_attrs() hook, which does some additional work like
- * ensuring that route @r is writable.
- *
- * The route @r may be read-only (with %REF_COW flag), in that case rw copy is
- * obtained by rte_cow() and @r is replaced. If @rte is originally rw, it may be
- * directly modified (and it is never copied).
- *
- * If the @old_attrs ptr is supplied, the function obtains another reference of
- * old cached &rta, that is necessary in some cases (see rte_cow_rta() for
- * details). It is freed by rte_store_tmp_attrs(), or manually by rta_free().
+ * rte_free - delete a &rte
+ * @e: &rte to be deleted
*
- * Generally, if caller ensures that @r is read-only (e.g. in route export) then
- * it may ignore @old_attrs (and set it to NULL), but must handle replacement of
- * @r. If caller ensures that @r is writable (e.g. in route import) then it may
- * ignore replacement of @r, but it must handle @old_attrs.
+ * rte_free() deletes the given &rte from the routing table it's linked to.
*/
void
-rte_make_tmp_attrs(rte **r, linpool *lp, rta **old_attrs)
+rte_free(rte *e)
{
- void (*make_tmp_attrs)(rte *r, linpool *lp);
- make_tmp_attrs = (*r)->attrs->src->proto->make_tmp_attrs;
-
- if (!make_tmp_attrs)
- return;
-
- /* We may need to keep ref to old attributes, will be freed in rte_store_tmp_attrs() */
- if (old_attrs)
- *old_attrs = rta_is_cached((*r)->attrs) ? rta_clone((*r)->attrs) : NULL;
-
- *r = rte_cow_rta(*r, lp);
- make_tmp_attrs(*r, lp);
+ rt_unlock_source(e->src);
+ if (rta_is_cached(e->attrs))
+ rta_free(e->attrs);
+ sl_free(rte_slab, e);
}
-/**
- * rte_store_tmp_attrs - store temporary route attributes back to private route fields
- * @r: route entry to be modified
- * @lp: linpool from which to allocate attributes
- * @old_attrs: temporary ref to old &rta
- *
- * This function stores temporary route attributes that were expanded by
- * rte_make_tmp_attrs() back to private route fields and also undefines them.
- * It is essentially a wrapper around protocol store_tmp_attrs() hook, which
- * does some additional work like shortcut if there is no change and cleanup
- * of @old_attrs reference obtained by rte_make_tmp_attrs().
- */
-static void
-rte_store_tmp_attrs(rte *r, linpool *lp, rta *old_attrs)
+static inline void
+rte_free_quick(rte *e)
{
- void (*store_tmp_attrs)(rte *rt, linpool *lp);
- store_tmp_attrs = r->attrs->src->proto->store_tmp_attrs;
-
- if (!store_tmp_attrs)
- return;
-
- ASSERT(!rta_is_cached(r->attrs));
-
- /* If there is no new ea_list, we just skip the temporary ea_list */
- ea_list *ea = r->attrs->eattrs;
- if (ea && (ea->flags & EALF_TEMP))
- r->attrs->eattrs = ea->next;
- else
- store_tmp_attrs(r, lp);
-
- /* Free ref we got in rte_make_tmp_attrs(), have to do rta_lookup() first */
- r->attrs = rta_lookup(r->attrs);
- rta_free(old_attrs);
+ rt_unlock_source(e->src);
+ rta_free(e->attrs);
+ sl_free(rte_slab, e);
}
-
static int /* Actually better or at least as good as */
rte_better(rte *new, rte *old)
{
@@ -797,20 +652,20 @@ rte_better(rte *new, rte *old)
if (!rte_is_valid(new))
return 0;
- if (new->pref > old->pref)
+ if (new->attrs->pref > old->attrs->pref)
return 1;
- if (new->pref < old->pref)
+ if (new->attrs->pref < old->attrs->pref)
return 0;
- if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
+ if (new->src->proto->proto != old->src->proto->proto)
{
/*
* If the user has configured protocol preferences, so that two different protocols
* have the same preference, try to break the tie by comparing addresses. Not too
* useful, but keeps the ordering of routes unambiguous.
*/
- return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
+ return new->src->proto->proto > old->src->proto->proto;
}
- if (better = new->attrs->src->proto->rte_better)
+ if (better = new->src->proto->rte_better)
return better(new, old);
return 0;
}
@@ -823,13 +678,13 @@ rte_mergable(rte *pri, rte *sec)
if (!rte_is_valid(pri) || !rte_is_valid(sec))
return 0;
- if (pri->pref != sec->pref)
+ if (pri->attrs->pref != sec->attrs->pref)
return 0;
- if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto)
+ if (pri->src->proto->proto != sec->src->proto->proto)
return 0;
- if (mergable = pri->attrs->src->proto->rte_mergable)
+ if (mergable = pri->src->proto->rte_mergable)
return mergable(pri, sec);
return 0;
@@ -838,8 +693,8 @@ rte_mergable(rte *pri, rte *sec)
static void
rte_trace(struct channel *c, rte *e, int dir, char *msg)
{
- log(L_TRACE "%s.%s %c %s %N %s",
- c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr,
+ log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
+ c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id,
rta_dest_name(e->attrs->dest));
}
@@ -869,7 +724,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
rt = rt0;
*rt_free = NULL;
- v = p->preexport ? p->preexport(p, &rt, pool) : 0;
+ v = p->preexport ? p->preexport(p, rt) : 0;
if (v < 0)
{
if (silent)
@@ -887,8 +742,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto accept;
}
- rte_make_tmp_attrs(&rt, pool, NULL);
-
v = filter && ((filter == FILTER_REJECT) ||
(f_run(filter, &rt, pool,
(silent ? FF_SILENT : 0)) > F_ACCEPT));
@@ -902,12 +755,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto reject;
}
-#ifdef CONFIG_PIPE
- /* Pipes need rte with stored tmpattrs, remaining protocols need expanded tmpattrs */
- if (p->proto == &proto_pipe)
- rte_store_tmp_attrs(rt, pool, NULL);
-#endif
-
accept:
if (rt != rt0)
*rt_free = rt;
@@ -951,8 +798,14 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
/* Apply export table */
- if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
- return;
+ struct rte *old_exported = NULL;
+ if (c->out_table)
+ {
+ if (!rte_update_out(c, net->n.addr, new, old, &old_exported, refeed))
+ return;
+ }
+ else if (c->out_filter == FILTER_ACCEPT)
+ old_exported = old;
if (new)
stats->exp_updates_accepted++;
@@ -982,6 +835,9 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
p->rt_notify(p, c, net, new, old);
+
+ if (c->out_table && old_exported)
+ rte_free_quick(old_exported);
}
static void
@@ -1341,27 +1197,6 @@ rte_validate(rte *e)
return 1;
}
-/**
- * rte_free - delete a &rte
- * @e: &rte to be deleted
- *
- * rte_free() deletes the given &rte from the routing table it's linked to.
- */
-void
-rte_free(rte *e)
-{
- if (rta_is_cached(e->attrs))
- rta_free(e->attrs);
- sl_free(rte_slab, e);
-}
-
-static inline void
-rte_free_quick(rte *e)
-{
- rta_free(e->attrs);
- sl_free(rte_slab, e);
-}
-
static int
rte_same(rte *x, rte *y)
{
@@ -1369,8 +1204,7 @@ rte_same(rte *x, rte *y)
return
x->attrs == y->attrs &&
x->pflags == y->pflags &&
- x->pref == y->pref &&
- (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)) &&
+ x->src == y->src &&
rte_is_filtered(x) == rte_is_filtered(y);
}
@@ -1391,7 +1225,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
- if (old->attrs->src == src)
+ if (old->src == src)
{
/* If there is the same route in the routing table but from
* a different sender, then there are two paths from the
@@ -1674,26 +1508,6 @@ rte_update_unlock(void)
lp_flush(rte_update_pool);
}
-static inline void
-rte_hide_dummy_routes(net *net, rte **dummy)
-{
- if (net->routes && net->routes->attrs->source == RTS_DUMMY)
- {
- *dummy = net->routes;
- net->routes = (*dummy)->next;
- }
-}
-
-static inline void
-rte_unhide_dummy_routes(net *net, rte **dummy)
-{
- if (*dummy)
- {
- (*dummy)->next = net->routes;
- net->routes = *dummy;
- }
-}
-
/**
* rte_update - enter a new update to a routing table
* @table: table to be updated
@@ -1742,7 +1556,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
// struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
const struct filter *filter = c->in_filter;
- rte *dummy = NULL;
net *nn;
ASSERT(c->channel_state == CS_UP);
@@ -1758,9 +1571,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
new->net = nn;
new->sender = c;
- if (!new->pref)
- new->pref = c->preference;
-
stats->imp_updates_received++;
if (!rte_validate(new))
{
@@ -1782,9 +1592,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
}
else if (filter)
{
- rta *old_attrs = NULL;
- rte_make_tmp_attrs(&new, rte_update_pool, &old_attrs);
-
int fr = f_run(filter, &new, rte_update_pool, 0);
if (fr > F_ACCEPT)
{
@@ -1792,15 +1599,10 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
rte_trace_in(D_FILTERS, c, new, "filtered out");
if (! c->in_keep_filtered)
- {
- rta_free(old_attrs);
goto drop;
- }
new->flags |= REF_FILTERED;
}
-
- rte_store_tmp_attrs(new, rte_update_pool, old_attrs);
}
if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
@@ -1824,9 +1626,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
recalc:
/* And recalculate the best route */
- rte_hide_dummy_routes(nn, &dummy);
rte_recalculate(c, nn, new, src);
- rte_unhide_dummy_routes(nn, &dummy);
rte_update_unlock();
return;
@@ -1855,7 +1655,7 @@ static inline void
rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
{
rte_update_lock();
- rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
+ rte_recalculate(old->sender, old->net, NULL, old->src);
rte_update_unlock();
}
@@ -1875,7 +1675,7 @@ rte_modify(rte *old)
new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
}
- rte_recalculate(old->sender, old->net, new, old->attrs->src);
+ rte_recalculate(old->sender, old->net, new, old->src);
}
rte_update_unlock();
@@ -1894,12 +1694,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter)
rte_update_lock();
/* Rest is stripped down export_filter() */
- int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0;
+ int v = p->preexport ? p->preexport(p, rt) : 0;
if (v == RIC_PROCESS)
- {
- rte_make_tmp_attrs(&rt, rte_update_pool, NULL);
v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
- }
/* Discard temporary rte */
if (rt != n->routes)
@@ -1999,10 +1796,8 @@ rte_dump(rte *e)
{
net *n = e->net;
debug("%-1N ", n->n.addr);
- debug("PF=%02x pref=%d ", e->pflags, e->pref);
+ debug("PF=%02x ", e->pflags);
rta_dump(e->attrs);
- if (e->attrs->src->proto->proto->dump_attrs)
- e->attrs->src->proto->proto->dump_attrs(e);
debug("\n");
}
@@ -2716,11 +2511,12 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32));
rta_apply_hostentry(a, old->attrs->hostentry, &mls);
- a->aflags = 0;
+ a->cached = 0;
rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte));
e->attrs = rta_lookup(a);
+ rt_lock_source(e->src);
return e;
}
@@ -2844,12 +2640,16 @@ static rte *
rt_flowspec_update_rte(rtable *tab, rte *r)
{
#ifdef CONFIG_BGP
- if ((r->attrs->source != RTS_BGP) || !r->u.bgp.base_table)
+ if (r->attrs->source != RTS_BGP)
+ return NULL;
+
+ struct bgp_channel *bc = (struct bgp_channel *) r->sender;
+ if (!bc->base_table)
return NULL;
const net_addr *n = r->net->n.addr;
- struct bgp_proto *p = (void *) r->attrs->src->proto;
- int valid = rt_flowspec_check(r->u.bgp.base_table, tab, n, r->attrs, p->is_interior);
+ struct bgp_proto *p = (void *) r->src->proto;
+ int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
if (dest == r->attrs->dest)
@@ -2858,7 +2658,7 @@ rt_flowspec_update_rte(rtable *tab, rte *r)
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, r->attrs, rta_size(r->attrs));
a->dest = dest;
- a->aflags = 0;
+ a->cached = 0;
rte *new = sl_alloc(rte_slab);
memcpy(new, r, sizeof(rte));
@@ -2898,8 +2698,8 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
- if (e->attrs->src->proto->rte_recalculate)
- e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
+ if (e->src->proto->rte_recalculate)
+ e->src->proto->rte_recalculate(tab, n, new, e, NULL);
if (e != old_best)
rte_free_quick(e);
@@ -3232,9 +3032,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
{
net = net_get(tab, n);
- if (!new->pref)
- new->pref = c->preference;
-
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
}
@@ -3248,7 +3045,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
/* Find the old rte */
for (pos = &net->routes; old = *pos; pos = &old->next)
- if (old->attrs->src == src)
+ if (old->src == src)
{
if (new && rte_same(old, new))
{
@@ -3353,7 +3150,7 @@ rt_reload_channel(struct channel *c)
return 0;
}
- rte_update2(c, e->net->n.addr, rte_do_cow(e), e->attrs->src);
+ rte_update2(c, e->net->n.addr, rte_do_cow(e), e->src);
}
c->reload_next_rte = NULL;
@@ -3426,7 +3223,7 @@ again:
*/
int
-rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed)
+rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **old_exported, int refeed)
{
struct rtable *tab = c->out_table;
struct rte_src *src;
@@ -3436,9 +3233,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
if (new)
{
net = net_get(tab, n);
- src = new->attrs->src;
-
- rte_store_tmp_attrs(new, rte_update_pool, NULL);
+ src = new->src;
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
@@ -3446,7 +3241,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
else
{
net = net_find(tab, n);
- src = old0->attrs->src;
+ src = old0->src;
if (!net)
goto drop_withdraw;
@@ -3454,7 +3249,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
/* Find the old rte */
for (pos = &net->routes; old = *pos; pos = &old->next)
- if ((c->ra_mode != RA_ANY) || (old->attrs->src == src))
+ if ((c->ra_mode != RA_ANY) || (old->src == src))
{
if (new && rte_same(old, new))
{
@@ -3472,7 +3267,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
/* Remove the old rte */
*pos = old->next;
- rte_free_quick(old);
+ *old_exported = old;
tab->rt_count--;
break;
@@ -3679,36 +3474,12 @@ rt_get_igp_metric(rte *rt)
if (ea)
return ea->u.data;
- rta *a = rt->attrs;
-
-#ifdef CONFIG_OSPF
- if ((a->source == RTS_OSPF) ||
- (a->source == RTS_OSPF_IA) ||
- (a->source == RTS_OSPF_EXT1))
- return rt->u.ospf.metric1;
-#endif
-
-#ifdef CONFIG_RIP
- if (a->source == RTS_RIP)
- return rt->u.rip.metric;
-#endif
-
-#ifdef CONFIG_BGP
- if (a->source == RTS_BGP)
- {
- u64 metric = bgp_total_aigp_metric(rt);
- return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN);
- }
-#endif
-
-#ifdef CONFIG_BABEL
- if (a->source == RTS_BABEL)
- return rt->u.babel.metric;
-#endif
-
- if (a->source == RTS_DEVICE)
+ if (rt->attrs->source == RTS_DEVICE)
return 0;
+ if (rt->src->proto->rte_igp_metric)
+ return rt->src->proto->rte_igp_metric(rt);
+
return IGP_METRIC_UNKNOWN;
}
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 174fc9e2..30809000 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -641,13 +641,36 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
if (r)
{
rta a0 = {
- .src = p->p.main_source,
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
+ .pref = c->preference,
.from = r->neigh->addr,
.nh.gw = r->next_hop,
.nh.iface = r->neigh->ifa->iface,
+ .eattrs = alloca(sizeof(ea_list) + 3*sizeof(eattr)),
+ };
+
+ *a0.eattrs = (ea_list) { .count = 3 };
+ a0.eattrs->attrs[0] = (eattr) {
+ .id = EA_BABEL_METRIC,
+ .type = EAF_TYPE_INT,
+ .u.data = r->metric,
+ };
+
+ struct adata *ad = alloca(sizeof(struct adata) + sizeof(u64));
+ ad->length = sizeof(u64);
+ memcpy(ad->data, &(r->router_id), sizeof(u64));
+ a0.eattrs->attrs[1] = (eattr) {
+ .id = EA_BABEL_ROUTER_ID,
+ .type = EAF_TYPE_OPAQUE,
+ .u.ptr = ad,
+ };
+
+ a0.eattrs->attrs[2] = (eattr) {
+ .id = EA_BABEL_SEQNO,
+ .type = EAF_TYPE_INT,
+ .u.data = r->seqno,
};
/*
@@ -659,11 +682,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
a0.nh.flags = RNF_ONLINK;
rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a);
- rte->u.babel.seqno = r->seqno;
- rte->u.babel.metric = r->metric;
- rte->u.babel.router_id = r->router_id;
- rte->pflags = EA_ID_FLAG(EA_BABEL_METRIC) | EA_ID_FLAG(EA_BABEL_ROUTER_ID);
+ rte *rte = rte_get_temp(a, p->p.main_source);
e->unreachable = 0;
rte_update2(c, e->n.addr, rte, p->p.main_source);
@@ -672,17 +691,15 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
{
/* Unreachable */
rta a0 = {
- .src = p->p.main_source,
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNREACHABLE,
+ .pref = 1,
};
rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a);
- memset(&rte->u.babel, 0, sizeof(rte->u.babel));
+ rte *rte = rte_get_temp(a, p->p.main_source);
rte->pflags = 0;
- rte->pref = 1;
e->unreachable = 1;
rte_update2(c, e->n.addr, rte, p->p.main_source);
@@ -2010,7 +2027,13 @@ babel_dump(struct proto *P)
static void
babel_get_route_info(rte *rte, byte *buf)
{
- buf += bsprintf(buf, " (%d/%d) [%lR]", rte->pref, rte->u.babel.metric, rte->u.babel.router_id);
+ u64 rid = 0;
+ eattr *e = ea_find(rte->attrs->eattrs, EA_BABEL_ROUTER_ID);
+ if (e)
+ memcpy(&rid, e->u.ptr->data, sizeof(u64));
+
+ buf += bsprintf(buf, " (%d/%d) [%lR]", rte->attrs->pref,
+ ea_get_int(rte->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY), rid);
}
static int
@@ -2018,6 +2041,9 @@ babel_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
+ case EA_BABEL_SEQNO:
+ return GA_FULL;
+
case EA_BABEL_METRIC:
bsprintf(buf, "metric: %d", a->u.data);
return GA_FULL;
@@ -2231,38 +2257,16 @@ babel_kick_timer(struct babel_proto *p)
static int
-babel_preexport(struct proto *P, struct rte **new, struct linpool *pool UNUSED)
+babel_preexport(struct proto *P, struct rte *new)
{
- struct rta *a = (*new)->attrs;
-
+ struct rta *a = new->attrs;
/* Reject our own unreachable routes */
- if ((a->dest == RTD_UNREACHABLE) && (a->src->proto == P))
+ if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
return -1;
return 0;
}
-static void
-babel_make_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- struct adata *id = lp_alloc_adata(pool, sizeof(u64));
- memcpy(id->data, &rt->u.babel.router_id, sizeof(u64));
-
- rte_init_tmp_attrs(rt, pool, 2);
- rte_make_tmp_attr(rt, EA_BABEL_METRIC, EAF_TYPE_INT, rt->u.babel.metric);
- rte_make_tmp_attr(rt, EA_BABEL_ROUTER_ID, EAF_TYPE_OPAQUE, (uintptr_t) id);
-}
-
-static void
-babel_store_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 2);
- rt->u.babel.metric = rte_store_tmp_attr(rt, EA_BABEL_METRIC);
-
- /* EA_BABEL_ROUTER_ID is read-only, we do not really save the value */
- rte_store_tmp_attr(rt, EA_BABEL_ROUTER_ID);
-}
-
/*
* babel_rt_notify - core tells us about new route (possibly our own),
* so store it into our data structures.
@@ -2277,10 +2281,22 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
if (new)
{
/* Update */
- uint internal = (new->attrs->src->proto == P);
- uint rt_seqno = internal ? new->u.babel.seqno : p->update_seqno;
+ uint rt_seqno;
uint rt_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, 0);
- u64 rt_router_id = internal ? new->u.babel.router_id : p->router_id;
+ u64 rt_router_id = 0;
+
+ if (new->src->proto == P)
+ {
+ rt_seqno = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
+ eattr *e = ea_find(new->attrs->eattrs, EA_BABEL_ROUTER_ID);
+ if (e)
+ memcpy(&rt_router_id, e->u.ptr->data, sizeof(u64));
+ }
+ else
+ {
+ rt_seqno = p->update_seqno;
+ rt_router_id = p->router_id;
+ }
if (rt_metric > BABEL_INFINITY)
{
@@ -2323,15 +2339,16 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
static int
babel_rte_better(struct rte *new, struct rte *old)
{
- return new->u.babel.metric < old->u.babel.metric;
+ uint new_metric = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
+ uint old_metric = ea_find(old->attrs->eattrs, EA_BABEL_SEQNO)->u.data;
+
+ return new_metric < old_metric;
}
-static int
-babel_rte_same(struct rte *new, struct rte *old)
+static u32
+babel_rte_igp_metric(struct rte *rt)
{
- return ((new->u.babel.seqno == old->u.babel.seqno) &&
- (new->u.babel.metric == old->u.babel.metric) &&
- (new->u.babel.router_id == old->u.babel.router_id));
+ return ea_get_int(rt->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY);
}
@@ -2365,10 +2382,8 @@ babel_init(struct proto_config *CF)
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
P->preexport = babel_preexport;
- P->make_tmp_attrs = babel_make_tmp_attrs;
- P->store_tmp_attrs = babel_store_tmp_attrs;
P->rte_better = babel_rte_better;
- P->rte_same = babel_rte_same;
+ P->rte_igp_metric = babel_rte_igp_metric;
return P;
}
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 84feb085..8b6da3c8 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -28,6 +28,7 @@
#define EA_BABEL_METRIC EA_CODE(PROTOCOL_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(PROTOCOL_BABEL, 1)
+#define EA_BABEL_SEQNO EA_CODE(PROTOCOL_BABEL, 2)
#define BABEL_MAGIC 42
#define BABEL_VERSION 2
diff --git a/proto/bfd/io.c b/proto/bfd/io.c
index 1cd9365a..e696cc89 100644
--- a/proto/bfd/io.c
+++ b/proto/bfd/io.c
@@ -482,6 +482,8 @@ birdloop_main(void *arg)
birdloop_set_current(loop);
+ tmp_init(loop->pool);
+
pthread_mutex_lock(&loop->mutex);
while (1)
{
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 1f927cbd..65e87c96 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -374,6 +374,13 @@ bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad)
return *metric < IGP_METRIC_UNKNOWN;
}
+u32
+bgp_rte_igp_metric(struct rte *rt)
+{
+ u64 metric = bgp_total_aigp_metric(rt);
+ return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN);
+}
+
/*
* Attribute hooks
@@ -1668,10 +1675,9 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
*/
int
-bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
+bgp_preexport(struct proto *P, rte *e)
{
- rte *e = *new;
- struct proto *SRC = e->attrs->src->proto;
+ struct proto *SRC = e->src->proto;
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
@@ -1730,7 +1736,7 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
static ea_list *
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
{
- struct proto *SRC = e->attrs->src->proto;
+ struct proto *SRC = e->src->proto;
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
ea_list *attrs = attrs0;
@@ -1854,7 +1860,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
if (new)
{
- struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2);
+ struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, tmp_linpool);
/* Error during attribute processing */
if (!attrs)
@@ -1862,14 +1868,12 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
/* If attributes are invalid, we fail back to withdraw */
buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
- path = new->attrs->src->global_id;
-
- lp_flush(bgp_linpool2);
+ path = new->src->global_id;
}
else
{
buck = bgp_get_withdraw_bucket(c);
- path = old->attrs->src->global_id;
+ path = old->src->global_id;
}
px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
@@ -1889,34 +1893,44 @@ bgp_get_neighbor(rte *r)
return as;
/* If AS_PATH is not defined, we treat rte as locally originated */
- struct bgp_proto *p = (void *) r->attrs->src->proto;
+ struct bgp_proto *p = (void *) r->src->proto;
return p->cf->confederation ?: p->local_as;
}
static inline int
rte_stale(rte *r)
{
- if (r->u.bgp.stale < 0)
+ if (r->pflags & BGP_REF_STALE)
+ return 1;
+
+ if (r->pflags & BGP_REF_NOT_STALE)
+ return 0;
+
+ /* If staleness is unknown, compute and cache it */
+ eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
+ if (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE))
{
- /* If staleness is unknown, compute and cache it */
- eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
- r->u.bgp.stale = a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE);
+ r->pflags |= BGP_REF_STALE;
+ return 1;
+ }
+ else
+ {
+ r->pflags |= BGP_REF_NOT_STALE;
+ return 0;
}
-
- return r->u.bgp.stale;
}
int
bgp_rte_better(rte *new, rte *old)
{
- struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->src->proto;
- struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->src->proto;
+ struct bgp_proto *new_bgp = (struct bgp_proto *) new->src->proto;
+ struct bgp_proto *old_bgp = (struct bgp_proto *) old->src->proto;
eattr *x, *y;
u32 n, o;
/* Skip suppressed routes (see bgp_rte_recalculate()) */
- n = new->u.bgp.suppressed;
- o = old->u.bgp.suppressed;
+ n = new->pflags & BGP_REF_SUPPRESSED;
+ o = old->pflags & BGP_REF_SUPPRESSED;
if (n > o)
return 0;
if (n < o)
@@ -2054,23 +2068,20 @@ bgp_rte_better(rte *new, rte *old)
int
bgp_rte_mergable(rte *pri, rte *sec)
{
- struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->attrs->src->proto;
- struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->attrs->src->proto;
+ struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->src->proto;
+ struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->src->proto;
eattr *x, *y;
u32 p, s;
/* Skip suppressed routes (see bgp_rte_recalculate()) */
- if (pri->u.bgp.suppressed != sec->u.bgp.suppressed)
+ /* LLGR draft - depreference stale routes */
+ if (pri->pflags != sec->pflags)
return 0;
/* RFC 4271 9.1.2.1. Route resolvability test */
if (rte_resolvable(pri) != rte_resolvable(sec))
return 0;
- /* LLGR draft - depreference stale routes */
- if (rte_stale(pri) != rte_stale(sec))
- return 0;
-
/* Start with local preferences */
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
@@ -2133,13 +2144,13 @@ bgp_rte_mergable(rte *pri, rte *sec)
static inline int
same_group(rte *r, u32 lpref, u32 lasn)
{
- return (r->pref == lpref) && (bgp_get_neighbor(r) == lasn);
+ return (r->attrs->pref == lpref) && (bgp_get_neighbor(r) == lasn);
}
static inline int
use_deterministic_med(rte *r)
{
- struct proto *P = r->attrs->src->proto;
+ struct proto *P = r->src->proto;
return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
}
@@ -2148,9 +2159,9 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
{
rte *r, *s;
rte *key = new ? new : old;
- u32 lpref = key->pref;
+ u32 lpref = key->attrs->pref;
u32 lasn = bgp_get_neighbor(key);
- int old_suppressed = old ? old->u.bgp.suppressed : 0;
+ int old_suppressed = old ? !!(old->pflags & BGP_REF_SUPPRESSED) : 0;
/*
* Proper RFC 4271 path selection is a bit complicated, it cannot be
@@ -2202,11 +2213,11 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
*/
if (new)
- new->u.bgp.suppressed = 1;
+ new->pflags |= BGP_REF_SUPPRESSED;
if (old)
{
- old->u.bgp.suppressed = 1;
+ old->pflags |= BGP_REF_SUPPRESSED;
/* The fast case - replace not best with worse (or remove not best) */
if (old_suppressed && !(new && bgp_rte_better(new, old)))
@@ -2218,7 +2229,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
for (s=net->routes; rte_is_valid(s); s=s->next)
if (use_deterministic_med(s) && same_group(s, lpref, lasn))
{
- s->u.bgp.suppressed = 1;
+ s->pflags |= BGP_REF_SUPPRESSED;
if (!r || bgp_rte_better(s, r))
r = s;
}
@@ -2229,16 +2240,16 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
/* Found if new is mergable with best-in-group */
if (new && (new != r) && bgp_rte_mergable(r, new))
- new->u.bgp.suppressed = 0;
+ new->pflags &= ~BGP_REF_SUPPRESSED;
/* Found all existing routes mergable with best-in-group */
for (s=net->routes; rte_is_valid(s); s=s->next)
if (use_deterministic_med(s) && same_group(s, lpref, lasn))
if ((s != r) && bgp_rte_mergable(r, s))
- s->u.bgp.suppressed = 0;
+ s->pflags &= ~BGP_REF_SUPPRESSED;
/* Found best-in-group */
- r->u.bgp.suppressed = 0;
+ r->pflags &= ~BGP_REF_SUPPRESSED;
/*
* There are generally two reasons why we have to force
@@ -2286,7 +2297,7 @@ bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
r = rte_cow_rta(r, pool);
bgp_set_attr_ptr(&(r->attrs->eattrs), pool, BA_COMMUNITY, flags,
int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
- r->u.bgp.stale = 1;
+ r->pflags |= BGP_REF_STALE;
return r;
}
@@ -2371,9 +2382,9 @@ bgp_get_route_info(rte *e, byte *buf)
eattr *o = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
u32 origas;
- buf += bsprintf(buf, " (%d", e->pref);
+ buf += bsprintf(buf, " (%d", e->attrs->pref);
- if (e->u.bgp.suppressed)
+ if (e->pflags & BGP_REF_SUPPRESSED)
buf += bsprintf(buf, "-");
if (rte_stale(e))
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 619a816b..52400762 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -126,9 +126,7 @@
#include "bgp.h"
-struct linpool *bgp_linpool; /* Global temporary pool */
-struct linpool *bgp_linpool2; /* Global temporary pool for bgp_rt_notify() */
-static list bgp_sockets; /* Global list of listening sockets */
+static list STATIC_LIST_INIT(bgp_sockets); /* Global list of listening sockets */
static void bgp_connect(struct bgp_proto *p);
@@ -161,10 +159,6 @@ bgp_open(struct bgp_proto *p)
uint flags = p->cf->free_bind ? SKF_FREEBIND : 0;
uint flag_mask = SKF_FREEBIND;
- /* FIXME: Add some global init? */
- if (!bgp_linpool)
- init_list(&bgp_sockets);
-
/* We assume that cf->iface is defined iff cf->local_ip is link-local */
WALK_LIST(bs, bgp_sockets)
@@ -204,12 +198,6 @@ bgp_open(struct bgp_proto *p)
add_tail(&bgp_sockets, &bs->n);
- if (!bgp_linpool)
- {
- bgp_linpool = lp_new_default(proto_pool);
- bgp_linpool2 = lp_new_default(proto_pool);
- }
-
return 0;
err:
@@ -238,15 +226,6 @@ bgp_close(struct bgp_proto *p)
rfree(bs->sk);
rem_node(&bs->n);
mb_free(bs);
-
- if (!EMPTY_LIST(bgp_sockets))
- return;
-
- rfree(bgp_linpool);
- bgp_linpool = NULL;
-
- rfree(bgp_linpool2);
- bgp_linpool2 = NULL;
}
static inline int
@@ -1700,6 +1679,7 @@ bgp_init(struct proto_config *CF)
P->rte_mergable = bgp_rte_mergable;
P->rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
P->rte_modify = bgp_rte_modify_stale;
+ P->rte_igp_metric = bgp_rte_igp_metric;
p->cf = cf;
p->is_internal = (cf->local_as == cf->remote_as);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 4969c0b9..bff49c3a 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -20,7 +20,6 @@
#include "lib/hash.h"
#include "lib/socket.h"
-struct linpool;
struct eattr;
@@ -203,6 +202,10 @@ struct bgp_channel_config {
#define BGP_BFD_GRACEFUL 2 /* BFD down triggers graceful restart */
+/* rte->pflags */
+#define BGP_REF_SUPPRESSED 0x1 /* Used for deterministic MED comparison */
+#define BGP_REF_STALE 0x2 /* Route is LLGR_STATE */
+#define BGP_REF_NOT_STALE 0x4 /* Route is NOT LLGR_STATE */
struct bgp_af_caps {
u32 afi;
@@ -454,7 +457,6 @@ struct bgp_parse_state {
jmp_buf err_jmpbuf;
struct hostentry *hostentry;
- struct rtable *base_table;
adata *mpls_labels;
/* Cached state for bgp_rte_update() */
@@ -495,9 +497,6 @@ bgp_parse_error(struct bgp_parse_state *s, uint subcode)
longjmp(s->err_jmpbuf, 1);
}
-extern struct linpool *bgp_linpool;
-extern struct linpool *bgp_linpool2;
-
void bgp_start_timer(timer *t, uint value);
void bgp_check_config(struct bgp_config *c);
@@ -588,8 +587,9 @@ int bgp_rte_better(struct rte *, struct rte *);
int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
+u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
-int bgp_preexport(struct proto *, struct rte **, struct linpool *);
+int bgp_preexport(struct proto *, struct rte *);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *buf);
int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index f13625e2..66f14150 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1025,9 +1025,6 @@ bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
- /* Set rte.bgp.base_table later from this state variable */
- s->base_table = c->base_table;
-
/* Invalidate cached rta if dest changes */
if (s->cached_rta && (s->cached_rta->dest != a->dest))
{
@@ -1386,8 +1383,6 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
/* Prepare cached route attributes */
if (s->cached_rta == NULL)
{
- a0->src = s->last_src;
-
/* Workaround for rta_lookup() breaking eattrs */
ea_list *ea = a0->eattrs;
s->cached_rta = rta_lookup(a0);
@@ -1395,12 +1390,9 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
}
rta *a = rta_clone(s->cached_rta);
- rte *e = rte_get_temp(a);
+ rte *e = rte_get_temp(a, s->last_src);
e->pflags = 0;
- e->u.bgp.suppressed = 0;
- e->u.bgp.stale = -1;
- e->u.bgp.base_table = s->base_table;
rte_update3(&s->channel->c, n, e, s->last_src);
}
@@ -2335,7 +2327,7 @@ again: ;
struct bgp_write_state s = {
.proto = p,
.channel = c,
- .pool = bgp_linpool,
+ .pool = tmp_linpool,
.mp_reach = (c->afi != BGP_AF_IPV4) || c->ext_next_hop,
.as4_session = p->as4_session,
.add_path = c->add_path_tx,
@@ -2464,8 +2456,6 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
s->last_id = 0;
s->last_src = s->proto->p.main_source;
- s->base_table = NULL;
-
/*
* IPv4 BGP and MP-BGP may be used together in one update, therefore we do not
* add BA_NEXT_HOP in bgp_decode_attrs(), but we add it here independently for
@@ -2481,6 +2471,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
a->scope = SCOPE_UNIVERSE;
a->from = s->proto->remote_ip;
a->eattrs = ea;
+ a->pref = c->c.preference;
c->desc->decode_next_hop(s, nh, nh_len, a);
bgp_finish_attrs(s, a);
@@ -2518,7 +2509,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
/* Initialize parse state */
struct bgp_parse_state s = {
.proto = p,
- .pool = bgp_linpool,
+ .pool = tmp_linpool,
.as4_session = p->as4_session,
};
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 8d97c860..e885611a 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -472,9 +472,9 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
#ifdef CONFIG_BGP
/* Find peer index */
- if (r->attrs->src->proto->proto == &proto_bgp)
+ if (r->src->proto->proto == &proto_bgp)
{
- struct bgp_proto *p = (void *) r->attrs->src->proto;
+ struct bgp_proto *p = (void *) r->src->proto;
struct mrt_peer_entry *n =
HASH_FIND(s->peer_hash, PEER, p->remote_id, p->remote_as, p->remote_ip);
@@ -488,7 +488,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
/* Path Identifier */
if (s->add_path)
- mrt_put_u32(b, r->attrs->src->private_id);
+ mrt_put_u32(b, r->src->private_id);
/* Route Attributes */
mrt_put_u16(b, 0);
@@ -519,14 +519,12 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
continue;
/* Skip routes that should be reported in the other phase */
- if (!s->always_add_path && (!rt->attrs->src->private_id != !s->add_path))
+ if (!s->always_add_path && (!rt->src->private_id != !s->add_path))
{
s->want_add_path = 1;
continue;
}
- rte_make_tmp_attrs(&rt, s->linpool, NULL);
-
if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT)
mrt_rib_table_entry(s, rt);
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index f38b8210..4cd45033 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -522,7 +522,10 @@ static inline void
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
{
struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
+
+ n->n = (node) {};
add_tail(&ifa->nbma_list, NODE n);
+
n->ip = src->ip;
n->eligible = src->eligible;
n->found = found;
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index ba8c2e2b..f9aa6cd1 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -107,12 +107,10 @@
#include <stdlib.h>
#include "ospf.h"
-static int ospf_preexport(struct proto *P, rte **new, struct linpool *pool);
-static void ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
-static void ospf_store_tmp_attrs(struct rte *rt, struct linpool *pool);
+static int ospf_preexport(struct proto *P, rte *new);
static void ospf_reload_routes(struct channel *C);
static int ospf_rte_better(struct rte *new, struct rte *old);
-static int ospf_rte_same(struct rte *new, struct rte *old);
+static u32 ospf_rte_igp_metric(struct rte *rt);
static void ospf_disp(timer *timer);
@@ -378,10 +376,8 @@ ospf_init(struct proto_config *CF)
P->reload_routes = ospf_reload_routes;
P->feed_begin = ospf_feed_begin;
P->feed_end = ospf_feed_end;
- P->make_tmp_attrs = ospf_make_tmp_attrs;
- P->store_tmp_attrs = ospf_store_tmp_attrs;
P->rte_better = ospf_rte_better;
- P->rte_same = ospf_rte_same;
+ P->rte_igp_metric = ospf_rte_igp_metric;
return P;
}
@@ -390,7 +386,9 @@ ospf_init(struct proto_config *CF)
static int
ospf_rte_better(struct rte *new, struct rte *old)
{
- if (new->u.ospf.metric1 == LSINFINITY)
+ u32 new_metric1 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+
+ if (new_metric1 == LSINFINITY)
return 0;
if(new->attrs->source < old->attrs->source) return 1;
@@ -398,27 +396,27 @@ ospf_rte_better(struct rte *new, struct rte *old)
if(new->attrs->source == RTS_OSPF_EXT2)
{
- if(new->u.ospf.metric2 < old->u.ospf.metric2) return 1;
- if(new->u.ospf.metric2 > old->u.ospf.metric2) return 0;
+ u32 old_metric2 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
+ u32 new_metric2 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY);
+ if(new_metric2 < old_metric2) return 1;
+ if(new_metric2 > old_metric2) return 0;
}
- if (new->u.ospf.metric1 < old->u.ospf.metric1)
+ u32 old_metric1 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+ if (new_metric1 < old_metric1)
return 1;
return 0; /* Old is shorter or same */
}
-static int
-ospf_rte_same(struct rte *new, struct rte *old)
+static u32
+ospf_rte_igp_metric(struct rte *rt)
{
- /* new->attrs == old->attrs always */
- return
- new->u.ospf.metric1 == old->u.ospf.metric1 &&
- new->u.ospf.metric2 == old->u.ospf.metric2 &&
- new->u.ospf.tag == old->u.ospf.tag &&
- new->u.ospf.router_id == old->u.ospf.router_id;
-}
+ if (rt->attrs->source == RTS_OSPF_EXT2)
+ return IGP_METRIC_UNKNOWN;
+ return ea_get_int(rt->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY);
+}
void
ospf_schedule_rtcalc(struct ospf_proto *p)
@@ -484,14 +482,13 @@ ospf_disp(timer * timer)
* import to the filters.
*/
static int
-ospf_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
+ospf_preexport(struct proto *P, rte *e)
{
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_area *oa = ospf_main_area(p);
- rte *e = *new;
/* Reject our own routes */
- if (e->attrs->src->proto == P)
+ if (e->src->proto == P)
return -1;
/* Do not export routes to stub areas */
@@ -501,26 +498,6 @@ ospf_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
return 0;
}
-static void
-ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 4);
- rte_make_tmp_attr(rt, EA_OSPF_METRIC1, EAF_TYPE_INT, rt->u.ospf.metric1);
- rte_make_tmp_attr(rt, EA_OSPF_METRIC2, EAF_TYPE_INT, rt->u.ospf.metric2);
- rte_make_tmp_attr(rt, EA_OSPF_TAG, EAF_TYPE_INT, rt->u.ospf.tag);
- rte_make_tmp_attr(rt, EA_OSPF_ROUTER_ID, EAF_TYPE_ROUTER_ID, rt->u.ospf.router_id);
-}
-
-static void
-ospf_store_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 4);
- rt->u.ospf.metric1 = rte_store_tmp_attr(rt, EA_OSPF_METRIC1);
- rt->u.ospf.metric2 = rte_store_tmp_attr(rt, EA_OSPF_METRIC2);
- rt->u.ospf.tag = rte_store_tmp_attr(rt, EA_OSPF_TAG);
- rt->u.ospf.router_id = rte_store_tmp_attr(rt, EA_OSPF_ROUTER_ID);
-}
-
/**
* ospf_shutdown - Finish of OSPF instance
* @P: OSPF protocol instance
@@ -558,6 +535,9 @@ ospf_shutdown(struct proto *P)
}
FIB_WALK_END;
+ if (tm_active(p->disp_timer))
+ tm_stop(p->disp_timer);
+
return PS_DOWN;
}
@@ -607,16 +587,20 @@ ospf_get_route_info(rte * rte, byte * buf)
}
buf += bsprintf(buf, " %s", type);
- buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1);
+ buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY));
if (rte->attrs->source == RTS_OSPF_EXT2)
- buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
+ buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY));
buf += bsprintf(buf, ")");
- if ((rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) && rte->u.ospf.tag)
+ if (rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2)
{
- buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
+ eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_TAG);
+ if (ea && (ea->u.data > 0))
+ buf += bsprintf(buf, " [%x]", ea->u.data);
}
- if (rte->u.ospf.router_id)
- buf += bsprintf(buf, " [%R]", rte->u.ospf.router_id);
+
+ eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_ROUTER_ID);
+ if (ea)
+ buf += bsprintf(buf, " [%R]", ea->u.data);
}
static int
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index faee49dc..471bb586 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -144,7 +144,7 @@ orta_compare(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
- if (old->type == RTS_DUMMY)
+ if (!old->type)
return 1;
/* Prefer intra-area to inter-area to externals */
@@ -195,7 +195,7 @@ orta_compare_asbr(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
- if (old->type == RTS_DUMMY)
+ if (!old->type)
return 1;
if (!p->rfc1583)
@@ -225,7 +225,7 @@ orta_compare_ext(const struct ospf_proto *p, const orta *new, const orta *old)
{
int r;
- if (old->type == RTS_DUMMY)
+ if (!old->type)
return 1;
/* 16.4 (6a) - prefer routes with lower type */
@@ -2053,32 +2053,54 @@ again1:
if (nf->n.type) /* Add the route */
{
rta a0 = {
- .src = p->p.main_source,
.source = nf->n.type,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh = *(nf->n.nhs),
+ .pref = p->p.main_channel->preference,
};
if (reload || ort_changed(nf, &a0))
{
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
+ a0.eattrs = alloca(sizeof(ea_list) + 4 * sizeof(eattr));
+ memset(a0.eattrs, 0, sizeof(ea_list));
- rta_free(nf->old_rta);
- nf->old_rta = rta_clone(a);
- e->u.ospf.metric1 = nf->old_metric1 = nf->n.metric1;
- e->u.ospf.metric2 = nf->old_metric2 = nf->n.metric2;
- e->u.ospf.tag = nf->old_tag = nf->n.tag;
- e->u.ospf.router_id = nf->old_rid = nf->n.rid;
- e->pflags = EA_ID_FLAG(EA_OSPF_METRIC1) | EA_ID_FLAG(EA_OSPF_ROUTER_ID);
+ nf->old_metric1 = nf->n.metric1;
+ nf->old_metric2 = nf->n.metric2;
+ nf->old_tag = nf->n.tag;
+ nf->old_rid = nf->n.rid;
+
+ a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
+ .id = EA_OSPF_METRIC1,
+ .type = EAF_TYPE_INT,
+ .u.data = nf->n.metric1,
+ };
if (nf->n.type == RTS_OSPF_EXT2)
- e->pflags |= EA_ID_FLAG(EA_OSPF_METRIC2);
+ a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
+ .id = EA_OSPF_METRIC2,
+ .type = EAF_TYPE_INT,
+ .u.data = nf->n.metric2,
+ };
- /* Perhaps onfly if tag is non-zero? */
if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2))
- e->pflags |= EA_ID_FLAG(EA_OSPF_TAG);
+ a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
+ .id = EA_OSPF_TAG,
+ .type = EAF_TYPE_INT,
+ .u.data = nf->n.tag,
+ };
+
+ a0.eattrs->attrs[a0.eattrs->count++] = (eattr) {
+ .id = EA_OSPF_ROUTER_ID,
+ .type = EAF_TYPE_ROUTER_ID,
+ .u.data = nf->n.rid,
+ };
+
+ rta *a = rta_lookup(&a0);
+ rte *e = rte_get_temp(a, p->p.main_source);
+
+ rta_free(nf->old_rta);
+ nf->old_rta = rta_clone(a);
DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
diff --git a/proto/perf/perf.c b/proto/perf/perf.c
index ba401a8a..52784c14 100644
--- a/proto/perf/perf.c
+++ b/proto/perf/perf.c
@@ -143,10 +143,10 @@ perf_loop(void *data)
if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
struct rta a0 = {
- .src = p->p.main_source,
.source = RTS_PERF,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
+ .pref = p->p.main_channel->preference,
.nh.iface = p->ifa->iface,
.nh.gw = gw,
.nh.weight = 1,
@@ -161,7 +161,7 @@ perf_loop(void *data)
clock_gettime(CLOCK_MONOTONIC, &ts_generated);
for (uint i=0; i<N; i++) {
- rte *e = rte_get_temp(p->data[i].a);
+ rte *e = rte_get_temp(p->data[i].a, p->p.main_source);
e->pflags = 0;
rte_update(P, &(p->data[i].net), e);
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index f991d09a..97862780 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -43,6 +43,10 @@
#include "pipe.h"
+#ifdef CONFIG_BGP
+#include "proto/bgp/bgp.h"
+#endif
+
static void
pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old)
{
@@ -65,34 +69,26 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
if (new)
{
+ src = new->src;
+
a = alloca(rta_size(new->attrs));
memcpy(a, new->attrs, rta_size(new->attrs));
- a->aflags = 0;
+ a->cached = 0;
a->hostentry = NULL;
- e = rte_get_temp(a);
- e->pflags = 0;
-
- /* Copy protocol specific embedded attributes. */
- memcpy(&(e->u), &(new->u), sizeof(e->u));
- e->pref = new->pref;
+ e = rte_get_temp(a, src);
e->pflags = new->pflags;
#ifdef CONFIG_BGP
/* Hack to cleanup cached value */
- if (e->attrs->src->proto->proto == &proto_bgp)
- {
- e->u.bgp.stale = -1;
- e->u.bgp.base_table = NULL;
- }
+ if (e->src->proto->proto == &proto_bgp)
+ e->pflags &= ~(BGP_REF_STALE | BGP_REF_NOT_STALE);
#endif
-
- src = a->src;
}
else
{
e = NULL;
- src = old->attrs->src;
+ src = old->src;
}
src_ch->table->pipe_busy = 1;
@@ -101,9 +97,9 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
}
static int
-pipe_preexport(struct proto *P, rte **ee, struct linpool *p UNUSED)
+pipe_preexport(struct proto *P, rte *e)
{
- struct proto *pp = (*ee)->sender->proto;
+ struct proto *pp = e->sender->proto;
if (pp == P)
return -1; /* Avoid local loops automatically */
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 66e8eb4b..540ff2a7 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -391,12 +391,12 @@ radv_net_match_trigger(struct radv_config *cf, net *n)
}
int
-radv_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
+radv_preexport(struct proto *P, rte *new)
{
// struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (P->cf);
- if (radv_net_match_trigger(cf, (*new)->net))
+ if (radv_net_match_trigger(cf, new->net))
return RIC_PROCESS;
if (cf->propagate_routes)
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index e1a235a0..a501a784 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -145,7 +145,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
{
/* Update */
rta a0 = {
- .src = p->p.main_source,
+ .pref = p->p.main_channel->preference,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
@@ -188,13 +188,27 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
a0.nh.iface = rt->from->ifa->iface;
}
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
+ a0.eattrs = alloca(sizeof(ea_list) + 3*sizeof(eattr));
+ memset(a0.eattrs, 0, sizeof(ea_list)); /* Zero-ing only the ea_list header */
+ a0.eattrs->count = 3;
+ a0.eattrs->attrs[0] = (eattr) {
+ .id = EA_RIP_METRIC,
+ .type = EAF_TYPE_INT,
+ .u.data = rt_metric,
+ };
+ a0.eattrs->attrs[1] = (eattr) {
+ .id = EA_RIP_TAG,
+ .type = EAF_TYPE_INT,
+ .u.data = rt_tag,
+ };
+ a0.eattrs->attrs[2] = (eattr) {
+ .id = EA_RIP_FROM,
+ .type = EAF_TYPE_PTR,
+ .u.data = (uintptr_t) a0.nh.iface,
+ };
- e->u.rip.from = a0.nh.iface;
- e->u.rip.metric = rt_metric;
- e->u.rip.tag = rt_tag;
- e->pflags = EA_ID_FLAG(EA_RIP_METRIC) | EA_ID_FLAG(EA_RIP_TAG);
+ rta *a = rta_lookup(&a0);
+ rte *e = rte_get_temp(a, p->p.main_source);
rte_update(&p->p, en->n.addr, e);
}
@@ -307,8 +321,9 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
if (new)
{
/* Update */
- u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1);
u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0);
+ u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1);
+ struct iface *rt_from = (struct iface *) ea_get_int(new->attrs->eattrs, EA_RIP_FROM, 0);
if (rt_metric > p->infinity)
{
@@ -339,7 +354,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
en->valid = RIP_ENTRY_VALID;
en->metric = rt_metric;
en->tag = rt_tag;
- en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
+ en->from = (new->src->proto == P) ? rt_from : NULL;
en->iface = new->attrs->nh.iface;
en->next_hop = new->attrs->nh.gw;
}
@@ -1068,37 +1083,24 @@ rip_reload_routes(struct channel *C)
rip_kick_timer(p);
}
-static void
-rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 2);
- rte_make_tmp_attr(rt, EA_RIP_METRIC, EAF_TYPE_INT, rt->u.rip.metric);
- rte_make_tmp_attr(rt, EA_RIP_TAG, EAF_TYPE_INT, rt->u.rip.tag);
-}
-
-static void
-rip_store_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 2);
- rt->u.rip.metric = rte_store_tmp_attr(rt, EA_RIP_METRIC);
- rt->u.rip.tag = rte_store_tmp_attr(rt, EA_RIP_TAG);
-}
-
static int
rip_rte_better(struct rte *new, struct rte *old)
{
- return new->u.rip.metric < old->u.rip.metric;
+ ASSERT_DIE(new->src == old->src);
+ struct rip_proto *p = (struct rip_proto *) new->src->proto;
+
+ u32 new_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, p->infinity);
+ u32 old_metric = ea_get_int(old->attrs->eattrs, EA_RIP_METRIC, p->infinity);
+
+ return new_metric < old_metric;
}
-static int
-rip_rte_same(struct rte *new, struct rte *old)
+static u32
+rip_rte_igp_metric(struct rte *rt)
{
- return ((new->u.rip.metric == old->u.rip.metric) &&
- (new->u.rip.tag == old->u.rip.tag) &&
- (new->u.rip.from == old->u.rip.from));
+ return ea_get_int(rt->attrs->eattrs, EA_RIP_METRIC, IGP_METRIC_UNKNOWN);
}
-
static void
rip_postconfig(struct proto_config *CF)
{
@@ -1120,10 +1122,8 @@ rip_init(struct proto_config *CF)
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
P->reload_routes = rip_reload_routes;
- P->make_tmp_attrs = rip_make_tmp_attrs;
- P->store_tmp_attrs = rip_store_tmp_attrs;
P->rte_better = rip_rte_better;
- P->rte_same = rip_rte_same;
+ P->rte_igp_metric = rip_rte_igp_metric;
return P;
}
@@ -1198,10 +1198,14 @@ rip_reconfigure(struct proto *P, struct proto_config *CF)
static void
rip_get_route_info(rte *rte, byte *buf)
{
- buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
+ struct rip_proto *p = (struct rip_proto *) rte->src->proto;
+ u32 rt_metric = ea_get_int(rte->attrs->eattrs, EA_RIP_METRIC, p->infinity);
+ u32 rt_tag = ea_get_int(rte->attrs->eattrs, EA_RIP_TAG, 0);
+
+ buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rt_metric);
- if (rte->u.rip.tag)
- bsprintf(buf, " [%04x]", rte->u.rip.tag);
+ if (rt_tag)
+ bsprintf(buf, " [%04x]", rt_tag);
}
static int
diff --git a/proto/rip/rip.h b/proto/rip/rip.h
index 8d347000..f8713c4a 100644
--- a/proto/rip/rip.h
+++ b/proto/rip/rip.h
@@ -197,6 +197,7 @@ struct rip_rte
#define EA_RIP_METRIC EA_CODE(PROTOCOL_RIP, 0)
#define EA_RIP_TAG EA_CODE(PROTOCOL_RIP, 1)
+#define EA_RIP_FROM EA_CODE(PROTOCOL_RIP, 2)
static inline int rip_is_v2(struct rip_proto *p)
{ return p->rip2; }
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index ab0837f3..be3d19ab 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -121,18 +121,18 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
struct rpki_proto *p = cache->p;
rta a0 = {
- .src = p->p.main_source,
+ .pref = channel->preference,
.source = RTS_RPKI,
.scope = SCOPE_UNIVERSE,
.dest = RTD_NONE,
};
rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
+ rte *e = rte_get_temp(a, p->p.main_source);
e->pflags = 0;
- rte_update2(channel, &pfxr->n, e, a0.src);
+ rte_update2(channel, &pfxr->n, e, e->src);
}
void
diff --git a/proto/static/static.c b/proto/static/static.c
index 2789c1bb..6d3871cc 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -56,10 +56,11 @@ static void
static_announce_rte(struct static_proto *p, struct static_route *r)
{
rta *a = allocz(RTA_MAX_SIZE);
- a->src = static_get_source(p, r->index);
+ struct rte_src *src = static_get_source(p, r->index);
a->source = RTS_STATIC;
a->scope = SCOPE_UNIVERSE;
a->dest = r->dest;
+ a->pref = p->p.main_channel->preference;
if (r->dest == RTD_UNICAST)
{
@@ -102,7 +103,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
return;
/* We skip rta_lookup() here */
- rte *e = rte_get_temp(a);
+ rte *e = rte_get_temp(a, src);
e->pflags = 0;
if (r->cmds)
@@ -119,7 +120,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
e->net = NULL;
}
- rte_update2(p->p.main_channel, r->net, e, a->src);
+ rte_update2(p->p.main_channel, r->net, e, src);
r->state = SRS_CLEAN;
if (r->cmds)
@@ -131,7 +132,7 @@ withdraw:
if (r->state == SRS_DOWN)
return;
- rte_update2(p->p.main_channel, r->net, NULL, a->src);
+ rte_update2(p->p.main_channel, r->net, NULL, src);
r->state = SRS_DOWN;
}
@@ -721,9 +722,9 @@ static_get_route_info(rte *rte, byte *buf)
{
eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC);
if (a)
- buf += bsprintf(buf, " (%d/%u)", rte->pref, a->u.data);
+ buf += bsprintf(buf, " (%d/%u)", rte->attrs->pref, a->u.data);
else
- buf += bsprintf(buf, " (%d)", rte->pref);
+ buf += bsprintf(buf, " (%d)", rte->attrs->pref);
}
static void
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 521f43f3..efdb18a3 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -582,16 +582,21 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
done:
e = rte_get_temp(&a);
e->net = net;
- e->u.krt.src = src;
- e->u.krt.proto = src2;
- e->u.krt.seen = 0;
- e->u.krt.best = 0;
- e->u.krt.metric = 0;
+
+ ea_list *ea = alloca(sizeof(ea_list) + 1 * sizeof(eattr));
+ *ea = (ea_list) { .count = 1, .next = e->attrs->eattrs };
+ e->attrs->eattrs = ea;
+
+ ea->attrs[0] = (eattr) {
+ .id = EA_KRT_SOURCE,
+ .type = EAF_TYPE_INT,
+ .u.data = src2,
+ };
if (scan)
- krt_got_route(p, e);
+ krt_got_route(p, e, src);
else
- krt_got_route_async(p, e, new);
+ krt_got_route_async(p, e, new, src);
}
static void
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 29b744cb..e103c8ef 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -1397,8 +1397,6 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
if (p->af == AF_MPLS)
priority = 0;
- else if (a->source == RTS_DUMMY)
- priority = e->u.krt.metric;
else if (KRT_CF->sys.metric)
priority = KRT_CF->sys.metric;
else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
@@ -1580,18 +1578,28 @@ nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint
static void
nl_announce_route(struct nl_parse_state *s)
{
- rte *e = rte_get_temp(s->attrs);
+ rte *e = rte_get_temp(s->attrs, s->proto->p.main_source);
e->net = s->net;
- e->u.krt.src = s->krt_src;
- e->u.krt.proto = s->krt_proto;
- e->u.krt.seen = 0;
- e->u.krt.best = 0;
- e->u.krt.metric = s->krt_metric;
+
+ ea_list *ea = alloca(sizeof(ea_list) + 2 * sizeof(eattr));
+ *ea = (ea_list) { .count = 2, .next = e->attrs->eattrs };
+ e->attrs->eattrs = ea;
+
+ ea->attrs[0] = (eattr) {
+ .id = EA_KRT_SOURCE,
+ .type = EAF_TYPE_INT,
+ .u.data = s->krt_proto,
+ };
+ ea->attrs[1] = (eattr) {
+ .id = EA_KRT_METRIC,
+ .type = EAF_TYPE_INT,
+ .u.data = s->krt_metric,
+ };
if (s->scan)
- krt_got_route(s->proto, e);
+ krt_got_route(s->proto, e, s->krt_src);
else
- krt_got_route_async(s->proto, e, s->new);
+ krt_got_route_async(s->proto, e, s->new, s->krt_src);
s->net = NULL;
s->attrs = NULL;
@@ -1755,7 +1763,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
nl_announce_route(s);
rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE);
- ra->src = p->p.main_source;
ra->source = RTS_INHERIT;
ra->scope = SCOPE_UNIVERSE;
diff --git a/sysdep/unix/alloc.c b/sysdep/unix/alloc.c
index 0e944d57..755b5fa5 100644
--- a/sysdep/unix/alloc.c
+++ b/sysdep/unix/alloc.c
@@ -11,6 +11,7 @@
#include "lib/lists.h"
#include "lib/event.h"
+#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@@ -18,113 +19,169 @@
#include <sys/mman.h>
#endif
-#ifdef HAVE_MMAP
-#define KEEP_PAGES 512
+long page_size = 0;
-static u64 page_size = 0;
-static _Bool use_fake = 0;
+#ifdef HAVE_MMAP
+#define KEEP_PAGES_MAIN_MAX 256
+#define KEEP_PAGES_MAIN_MIN 8
+#define CLEANUP_PAGES_BULK 256
-uint pages_kept = 0;
-static list pages_list;
+_Static_assert(KEEP_PAGES_MAIN_MIN * 4 < KEEP_PAGES_MAIN_MAX);
-static void cleanup_pages(void *data);
-static event page_cleanup_event = { .hook = cleanup_pages };
+static _Bool use_fake = 0;
+#if DEBUGGING
+struct free_page {
+ node unused[42];
+ node n;
+};
#else
-static const u64 page_size = 4096; /* Fake page size */
+struct free_page {
+ node n;
+};
#endif
-u64 get_page_size(void)
+struct free_pages {
+ list pages;
+ u16 min, max; /* Minimal and maximal number of free pages kept */
+ uint cnt; /* Number of empty pages */
+ event cleanup;
+};
+
+static void global_free_pages_cleanup_event(void *);
+
+static struct free_pages global_free_pages = {
+ .min = KEEP_PAGES_MAIN_MIN,
+ .max = KEEP_PAGES_MAIN_MAX,
+ .cleanup = { .hook = global_free_pages_cleanup_event },
+};
+
+uint *pages_kept = &global_free_pages.cnt;
+
+static void *
+alloc_sys_page(void)
{
- if (page_size)
- return page_size;
+ void *ptr = mmap(NULL, page_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#ifdef HAVE_MMAP
- if (page_size = sysconf(_SC_PAGESIZE))
- {
- if ((u64_popcount(page_size) > 1) || (page_size > 16384))
- {
- /* Too big or strange page, use the aligned allocator instead */
- page_size = 4096;
- use_fake = 1;
- }
- return page_size;
- }
+ if (ptr == MAP_FAILED)
+ bug("mmap(%lu) failed: %m", page_size);
- bug("Page size must be non-zero");
-#endif
+ return ptr;
}
+extern int shutting_down; /* Shutdown requested. */
+
+#else // ! HAVE_MMAP
+#define use_fake 1
+#endif
+
void *
alloc_page(void)
{
-#ifdef HAVE_MMAP
- if (pages_kept)
- {
- node *page = TAIL(pages_list);
- rem_node(page);
- pages_kept--;
- memset(page, 0, get_page_size());
- return page;
- }
-
- if (!use_fake)
- {
- void *ret = mmap(NULL, get_page_size(), PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (ret == MAP_FAILED)
- bug("mmap(%lu) failed: %m", (long unsigned int) page_size);
- return ret;
- }
- else
-#endif
+ if (use_fake)
{
void *ptr = NULL;
int err = posix_memalign(&ptr, page_size, page_size);
+
if (err || !ptr)
bug("posix_memalign(%lu) failed", (long unsigned int) page_size);
+
return ptr;
}
+
+#ifdef HAVE_MMAP
+ struct free_pages *fps = &global_free_pages;
+
+ if (fps->cnt)
+ {
+ struct free_page *fp = SKIP_BACK(struct free_page, n, HEAD(fps->pages));
+ rem_node(&fp->n);
+ if ((--fps->cnt < fps->min) && !shutting_down)
+ ev_schedule(&fps->cleanup);
+
+ bzero(fp, page_size);
+ return fp;
+ }
+
+ return alloc_sys_page();
+#endif
}
void
free_page(void *ptr)
{
-#ifdef HAVE_MMAP
- if (!use_fake)
+ if (use_fake)
{
- if (!pages_kept)
- init_list(&pages_list);
+ free(ptr);
+ return;
+ }
+
+#ifdef HAVE_MMAP
+ struct free_pages *fps = &global_free_pages;
+ struct free_page *fp = ptr;
- memset(ptr, 0, sizeof(node));
- add_tail(&pages_list, ptr);
+ fp->n = (node) {};
+ add_tail(&fps->pages, &fp->n);
- if (++pages_kept > KEEP_PAGES)
- ev_schedule(&page_cleanup_event);
- }
- else
+ if ((++fps->cnt > fps->max) && !shutting_down)
+ ev_schedule(&fps->cleanup);
#endif
- free(ptr);
}
#ifdef HAVE_MMAP
static void
-cleanup_pages(void *data UNUSED)
+global_free_pages_cleanup_event(void *data UNUSED)
{
- for (uint seen = 0; (pages_kept > KEEP_PAGES) && (seen < KEEP_PAGES); seen++)
+ if (shutting_down)
+ return;
+
+ struct free_pages *fps = &global_free_pages;
+
+ while (fps->cnt / 2 < fps->min)
{
- void *ptr = HEAD(pages_list);
- rem_node(ptr);
- if (munmap(ptr, get_page_size()) == 0)
- pages_kept--;
-#ifdef ENOMEM
+ struct free_page *fp = alloc_sys_page();
+ fp->n = (node) {};
+ add_tail(&fps->pages, &fp->n);
+ fps->cnt++;
+ }
+
+ for (uint seen = 0; (seen < CLEANUP_PAGES_BULK) && (fps->cnt > fps->max / 2); seen++)
+ {
+ struct free_page *fp = SKIP_BACK(struct free_page, n, TAIL(fps->pages));
+ rem_node(&fp->n);
+
+ if (munmap(fp, page_size) == 0)
+ fps->cnt--;
else if (errno == ENOMEM)
- add_tail(&pages_list, ptr);
-#endif
+ add_head(&fps->pages, &fp->n);
else
- bug("munmap(%p) failed: %m", ptr);
+ bug("munmap(%p) failed: %m", fp);
}
-
- if (pages_kept > KEEP_PAGES)
- ev_schedule(&page_cleanup_event);
}
#endif
+
+void
+resource_sys_init(void)
+{
+#ifdef HAVE_MMAP
+ ASSERT_DIE(global_free_pages.cnt == 0);
+
+ if (!(page_size = sysconf(_SC_PAGESIZE)))
+ die("System page size must be non-zero");
+
+ if (u64_popcount(page_size) == 1)
+ {
+ struct free_pages *fps = &global_free_pages;
+
+ init_list(&fps->pages);
+ global_free_pages_cleanup_event(NULL);
+ return;
+ }
+
+ /* Too big or strange page, use the aligned allocator instead */
+ log(L_WARN "Got strange memory page size (%lu), using the aligned allocator instead", page_size);
+ use_fake = 1;
+#endif
+
+ page_size = 4096;
+}
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 4fd77453..8a116789 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -1854,8 +1854,8 @@ sk_read_ssh(sock *s)
/* sk_read() and sk_write() are called from BFD's event loop */
-int
-sk_read(sock *s, int revents)
+static inline int
+sk_read_noflush(sock *s, int revents)
{
switch (s->type)
{
@@ -1918,7 +1918,15 @@ sk_read(sock *s, int revents)
}
int
-sk_write(sock *s)
+sk_read(sock *s, int revents)
+{
+ int e = sk_read_noflush(s, revents);
+ tmp_flush();
+ return e;
+}
+
+static inline int
+sk_write_noflush(sock *s)
{
switch (s->type)
{
@@ -1966,6 +1974,14 @@ sk_write(sock *s)
}
}
+int
+sk_write(sock *s)
+{
+ int e = sk_write_noflush(s);
+ tmp_flush();
+ return e;
+}
+
int sk_is_ipv4(sock *s)
{ return s->af == AF_INET; }
@@ -1984,6 +2000,7 @@ sk_err(sock *s, int revents)
}
s->err_hook(s, se);
+ tmp_flush();
}
void
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 7c2614b1..7d7ec7e6 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -277,22 +277,23 @@ static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
* the same key.
*/
+static inline u32
+krt_metric(rte *a)
+{
+ eattr *ea = ea_find(a->attrs->eattrs, EA_KRT_METRIC);
+ return ea ? ea->u.data : 0;
+}
+
static inline int
krt_same_key(rte *a, rte *b)
{
- return a->u.krt.metric == b->u.krt.metric;
+ return (krt_metric(a) == krt_metric(b));
}
static inline int
krt_uptodate(rte *a, rte *b)
{
- if (a->attrs != b->attrs)
- return 0;
-
- if (a->u.krt.proto != b->u.krt.proto)
- return 0;
-
- return 1;
+ return (a->attrs == b->attrs);
}
static void
@@ -300,9 +301,7 @@ krt_learn_announce_update(struct krt_proto *p, rte *e)
{
net *n = e->net;
rta *aa = rta_clone(e->attrs);
- rte *ee = rte_get_temp(aa);
- ee->pflags = EA_ID_FLAG(EA_KRT_SOURCE) | EA_ID_FLAG(EA_KRT_METRIC);
- ee->u.krt = e->u.krt;
+ rte *ee = rte_get_temp(aa, p->p.main_source);
rte_update(&p->p, n->n.addr, ee);
}
@@ -331,7 +330,7 @@ krt_learn_scan(struct krt_proto *p, rte *e)
{
krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
rte_free(e);
- m->u.krt.seen = 1;
+ m->pflags |= KRT_REF_SEEN;
}
else
{
@@ -347,7 +346,7 @@ krt_learn_scan(struct krt_proto *p, rte *e)
{
e->next = n->routes;
n->routes = e;
- e->u.krt.seen = 1;
+ e->pflags |= KRT_REF_SEEN;
}
}
@@ -377,24 +376,23 @@ again:
ee = &n->routes;
while (e = *ee)
{
- if (e->u.krt.best)
+ if (e->pflags & KRT_REF_BEST)
old_best = e;
- if (!e->u.krt.seen)
+ if (!(e->pflags & KRT_REF_SEEN))
{
*ee = e->next;
rte_free(e);
continue;
}
- if (!best || best->u.krt.metric > e->u.krt.metric)
+ if (!best || krt_metric(best) > krt_metric(e))
{
best = e;
pbest = ee;
}
- e->u.krt.seen = 0;
- e->u.krt.best = 0;
+ e->pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST);
ee = &e->next;
}
if (!n->routes)
@@ -408,18 +406,18 @@ again:
goto again;
}
- best->u.krt.best = 1;
+ best->pflags |= KRT_REF_BEST;
*pbest = best->next;
best->next = n->routes;
n->routes = best;
if ((best != old_best) || p->reload)
{
- DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
+ DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best));
krt_learn_announce_update(p, best);
}
else
- DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
+ DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best));
}
FIB_ITERATE_END;
@@ -433,6 +431,9 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
net *n = net_get(p->krt_table, n0->n.addr);
rte *g, **gg, *best, **bestp, *old_best;
+ ASSERT(!e->attrs->cached);
+ e->attrs->pref = p->p.main_channel->preference;
+
e->attrs = rta_lookup(e->attrs);
old_best = n->routes;
@@ -476,18 +477,18 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
bestp = &n->routes;
for(gg=&n->routes; g=*gg; gg=&g->next)
{
- if (best->u.krt.metric > g->u.krt.metric)
+ if (krt_metric(best) > krt_metric(g))
{
best = g;
bestp = gg;
}
- g->u.krt.best = 0;
+ g->pflags &= ~KRT_REF_BEST;
}
if (best)
{
- best->u.krt.best = 1;
+ best->pflags |= KRT_REF_BEST;
*bestp = best->next;
best->next = n->routes;
n->routes = best;
@@ -528,12 +529,6 @@ krt_dump(struct proto *P)
rt_dump(p->krt_table);
}
-static void
-krt_dump_attrs(rte *e)
-{
- debug(" [m=%d,p=%d]", e->u.krt.metric, e->u.krt.proto);
-}
-
#endif
/*
@@ -582,8 +577,6 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
if (filter == FILTER_REJECT)
return NULL;
- rte_make_tmp_attrs(&rt, krt_filter_lp, NULL);
-
/* We could run krt_preexport() here, but it is already handled by krt_is_installed() */
if (filter == FILTER_ACCEPT)
@@ -624,13 +617,14 @@ krt_same_dest(rte *k, rte *e)
*/
void
-krt_got_route(struct krt_proto *p, rte *e)
+krt_got_route(struct krt_proto *p, rte *e, s8 src)
{
rte *new = NULL, *rt_free = NULL;
net *n = e->net;
+ e->pflags = 0;
#ifdef KRT_ALLOW_LEARN
- switch (e->u.krt.src)
+ switch (src)
{
case KRT_SRC_KERNEL:
goto ignore;
@@ -752,11 +746,12 @@ krt_prune(struct krt_proto *p)
}
void
-krt_got_route_async(struct krt_proto *p, rte *e, int new)
+krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
{
net *net = e->net;
+ e->pflags = 0;
- switch (e->u.krt.src)
+ switch (src)
{
case KRT_SRC_BIRD:
/* Should be filtered by the back end */
@@ -886,29 +881,11 @@ krt_scan_timer_kick(struct krt_proto *p)
* Updates
*/
-static void
-krt_make_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 2);
- rte_make_tmp_attr(rt, EA_KRT_SOURCE, EAF_TYPE_INT, rt->u.krt.proto);
- rte_make_tmp_attr(rt, EA_KRT_METRIC, EAF_TYPE_INT, rt->u.krt.metric);
-}
-
-static void
-krt_store_tmp_attrs(struct rte *rt, struct linpool *pool)
-{
- rte_init_tmp_attrs(rt, pool, 2);
- rt->u.krt.proto = rte_store_tmp_attr(rt, EA_KRT_SOURCE);
- rt->u.krt.metric = rte_store_tmp_attr(rt, EA_KRT_METRIC);
-}
-
static int
-krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
+krt_preexport(struct proto *P, rte *e)
{
// struct krt_proto *p = (struct krt_proto *) P;
- rte *e = *new;
-
- if (e->attrs->src->proto == P)
+ if (e->src->proto == P)
return -1;
if (!krt_capable(e))
@@ -983,14 +960,6 @@ krt_feed_end(struct channel *C)
}
-static int
-krt_rte_same(rte *a, rte *b)
-{
- /* src is always KRT_SRC_ALIEN and type is irrelevant */
- return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
-}
-
-
/*
* Protocol glue
*/
@@ -1049,9 +1018,6 @@ krt_init(struct proto_config *CF)
p->p.if_notify = krt_if_notify;
p->p.reload_routes = krt_reload_routes;
p->p.feed_end = krt_feed_end;
- p->p.make_tmp_attrs = krt_make_tmp_attrs;
- p->p.store_tmp_attrs = krt_store_tmp_attrs;
- p->p.rte_same = krt_rte_same;
krt_sys_init(p);
return &p->p;
@@ -1209,6 +1175,5 @@ struct protocol proto_unix_kernel = {
.get_attr = krt_get_attr,
#ifdef KRT_ALLOW_LEARN
.dump = krt_dump,
- .dump_attrs = krt_dump_attrs,
#endif
};
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 62228f08..20858cd7 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -24,6 +24,9 @@ struct kif_proto;
#define EA_KRT_SOURCE EA_CODE(PROTOCOL_KERNEL, 0)
#define EA_KRT_METRIC EA_CODE(PROTOCOL_KERNEL, 1)
+#define KRT_REF_SEEN 0x1 /* Seen in table */
+#define KRT_REF_BEST 0x2 /* Best in table */
+
/* Whenever we recognize our own routes, we allow learing of foreign routes */
#ifdef CONFIG_SELF_CONSCIOUS
@@ -76,8 +79,8 @@ extern pool *krt_pool;
struct proto_config * kif_init_config(int class);
void kif_request_scan(void);
-void krt_got_route(struct krt_proto *p, struct rte *e);
-void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
+void krt_got_route(struct krt_proto *p, struct rte *e, s8 src);
+void krt_got_route_async(struct krt_proto *p, struct rte *e, int new, s8 src);
static inline int
krt_get_sync_error(struct krt_proto *p, struct rte *e)
diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c
index 14d18c01..4e9df069 100644
--- a/sysdep/unix/log.c
+++ b/sysdep/unix/log.c
@@ -309,22 +309,15 @@ die(const char *msg, ...)
void
debug(const char *msg, ...)
{
-#define MAX_DEBUG_BUFSIZE 65536
+#define MAX_DEBUG_BUFSIZE 16384
va_list args;
- static uint bufsize = 4096;
- static char *buf = NULL;
-
- if (!buf)
- buf = mb_alloc(&root_pool, bufsize);
+ char buf[MAX_DEBUG_BUFSIZE];
va_start(args, msg);
if (dbgf)
{
- while (bvsnprintf(buf, bufsize, msg, args) < 0)
- if (bufsize >= MAX_DEBUG_BUFSIZE)
- bug("Extremely long debug output, split it.");
- else
- buf = mb_realloc(buf, (bufsize *= 2));
+ if (bvsnprintf(buf, MAX_DEBUG_BUFSIZE, msg, args) < 0)
+ bug("Extremely long debug output, split it.");
fputs(buf, dbgf);
}
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 392aff9d..cdf0a310 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -479,6 +479,14 @@ cli_err(sock *s, int err)
cli_free(s->data);
}
+static void
+cli_connect_err(sock *s UNUSED, int err)
+{
+ ASSERT_DIE(err);
+ if (config->cli_debug)
+ log(L_INFO "Failed to accept CLI connection: %s", strerror(err));
+}
+
static int
cli_connect(sock *s, uint size UNUSED)
{
@@ -507,6 +515,7 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
s = cli_sk = sk_new(cli_pool);
s->type = SK_UNIX_PASSIVE;
s->rx_hook = cli_connect;
+ s->err_hook = cli_connect_err;
s->rbsize = 1024;
s->fast_rx = 1;
diff --git a/test/birdtest.c b/test/birdtest.c
index 6ad743ce..ae05d1a5 100644
--- a/test/birdtest.c
+++ b/test/birdtest.c
@@ -20,6 +20,7 @@
#include "test/birdtest.h"
#include "lib/string.h"
+#include "lib/event.h"
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
@@ -119,6 +120,9 @@ bt_init(int argc, char *argv[])
clock_gettime(CLOCK_MONOTONIC, &bt_begin);
bt_suite_case_begin = bt_suite_begin = bt_begin;
+ resource_init();
+ ev_init_list(&global_event_list);
+
return;
usage:
@@ -172,6 +176,8 @@ int bt_run_test_fn(int (*fn)(const void *), const void *fn_arg, int timeout)
if (!bt_suite_result)
result = 0;
+ tmp_flush();
+
return result;
}
@@ -240,7 +246,7 @@ bt_log_result(int result, u64 time, const char *fmt, va_list argptr)
printf("%s\n", result_str);
if (do_die && !result)
- abort();
+ exit(1);
}
static u64
diff --git a/test/bt-utils.c b/test/bt-utils.c
index cbca3a6b..2a7799c3 100644
--- a/test/bt-utils.c
+++ b/test/bt-utils.c
@@ -60,7 +60,6 @@ bt_bird_init(void)
log_init_debug("");
log_switch(bt_verbose != 0, NULL, NULL);
- resource_init();
olock_init();
timer_init();
io_init();