diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/Makefile | 7 | ||||
-rw-r--r-- | nest/a-path.c | 4 | ||||
-rw-r--r-- | nest/a-path_test.c | 30 | ||||
-rw-r--r-- | nest/a-set_test.c | 51 | ||||
-rw-r--r-- | nest/cmds.c | 5 | ||||
-rw-r--r-- | nest/config.Y | 2 | ||||
-rw-r--r-- | nest/neighbor.c | 2 | ||||
-rw-r--r-- | nest/proto-hooks.c | 40 | ||||
-rw-r--r-- | nest/proto.c | 54 | ||||
-rw-r--r-- | nest/protocol.h | 23 | ||||
-rw-r--r-- | nest/route.h | 133 | ||||
-rw-r--r-- | nest/rt-attr.c | 65 | ||||
-rw-r--r-- | nest/rt-dev.c | 10 | ||||
-rw-r--r-- | nest/rt-fib.c | 2 | ||||
-rw-r--r-- | nest/rt-show.c | 13 | ||||
-rw-r--r-- | nest/rt-table.c | 378 |
16 files changed, 234 insertions, 585 deletions
diff --git a/nest/Makefile b/nest/Makefile index 884d3950..7d451ba4 100644 --- a/nest/Makefile +++ b/nest/Makefile @@ -1,7 +1,12 @@ -src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c +src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c proto-build.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,dev_build) + +$(proto-build-c): $(lastword $(MAKEFILE_LIST)) + $(E)echo GEN $@ + $(Q)echo "$(patsubst %,void %(void); ,$(PROTO_BUILD)) void protos_build_gen(void) { $(patsubst %, %(); ,$(PROTO_BUILD))}" > $@ tests_src := a-set_test.c a-path_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/nest/a-path.c b/nest/a-path.c index 2e34a3d1..badbc911 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -591,7 +591,7 @@ as_path_match_set(const struct adata *path, const struct f_tree *set) p += 2; for (i=0; i<n; i++) { - struct f_val v = {T_INT, .val.i = get_as(p)}; + struct f_val v = { .type = T_INT, .val.i = get_as(p)}; if (find_tree(set, &v)) return 1; p += BS; @@ -631,7 +631,7 @@ as_path_filter(struct linpool *pool, const struct adata *path, const struct f_tr if (set) { - struct f_val v = {T_INT, .val.i = as}; + struct f_val v = { .type = T_INT, .val.i = as}; match = !!find_tree(set, &v); } else 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/neighbor.c b/nest/neighbor.c index 1a31fb79..7cf9c85d 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -345,7 +345,7 @@ neigh_free(neighbor *n) { rem_node(&n->n); rem_node(&n->if_n); - sl_free(neigh_slab, n); + sl_free(n); } /** 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..7074f73a 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -23,9 +23,9 @@ #include "filter/f-inst.h" pool *proto_pool; -list proto_list; +list STATIC_LIST_INIT(proto_list); -static list protocol_list; +static list STATIC_LIST_INIT(protocol_list); struct protocol *class_to_protocol[PROTOCOL__MAX]; #define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); }) @@ -1651,6 +1651,8 @@ proto_build(struct protocol *p) /* FIXME: convert this call to some protocol hook */ extern void bfd_init_all(void); +void protos_build_gen(void); + /** * protos_build - build a protocol list * @@ -1663,44 +1665,7 @@ extern void bfd_init_all(void); void protos_build(void) { - init_list(&proto_list); - init_list(&protocol_list); - - proto_build(&proto_device); -#ifdef CONFIG_RADV - proto_build(&proto_radv); -#endif -#ifdef CONFIG_RIP - proto_build(&proto_rip); -#endif -#ifdef CONFIG_STATIC - proto_build(&proto_static); -#endif -#ifdef CONFIG_MRT - proto_build(&proto_mrt); -#endif -#ifdef CONFIG_OSPF - proto_build(&proto_ospf); -#endif -#ifdef CONFIG_PIPE - proto_build(&proto_pipe); -#endif -#ifdef CONFIG_BGP - proto_build(&proto_bgp); -#endif -#ifdef CONFIG_BFD - proto_build(&proto_bfd); - bfd_init_all(); -#endif -#ifdef CONFIG_BABEL - proto_build(&proto_babel); -#endif -#ifdef CONFIG_RPKI - proto_build(&proto_rpki); -#endif -#ifdef CONFIG_PERF - proto_build(&proto_perf); -#endif + protos_build_gen(); proto_pool = rp_new(&root_pool, "Protocols"); proto_shutdown_timer = tm_new(proto_pool); @@ -2243,8 +2208,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..d0810a8f 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 */ @@ -85,8 +84,8 @@ struct protocol { void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ }; -void protos_build(void); -void proto_build(struct protocol *); +void protos_build(void); /* Called from sysdep to initialize protocols */ +void proto_build(struct protocol *); /* Called from protocol to register itself */ void protos_preconfig(struct config *); void protos_commit(struct config *new, struct config *old, int force_restart, int type); struct proto * proto_spawn(struct proto_config *cf, uint disabled); @@ -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..80c53ba6 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 */ @@ -551,10 +502,13 @@ static inline int rte_is_reachable(rte *r) typedef struct eattr { word id; /* EA_CODE(PROTOCOL_..., protocol-dependent ID) */ byte flags; /* Protocol-dependent flags */ - byte type; /* Attribute type and several flags (EAF_...) */ + byte type:5; /* Attribute type */ + byte originated:1; /* The attribute has originated locally */ + byte fresh:1; /* An uncached attribute (e.g. modified in export filter) */ + byte undef:1; /* Explicitly undefined */ union { - u32 data; - const struct adata *ptr; /* Attribute data elsewhere */ + uintptr_t data; + const struct adata *ptr; /* Attribute data elsewhere */ } u; } eattr; @@ -562,7 +516,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) @@ -587,11 +540,9 @@ const char *ea_custom_name(uint ea); #define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */ #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 */ +#define EAF_TYPE_IFACE 0x16 /* Interface pointer stored in adata */ #define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ #define EAF_VAR_LENGTH 0x02 /* Attribute length is variable (part of type spec) */ -#define EAF_ORIGINATED 0x20 /* The attribute has originated locally */ -#define EAF_FRESH 0x40 /* An uncached attribute (e.g. modified in export filter) */ typedef struct adata { uint length; /* Length of data */ @@ -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 */ @@ -660,27 +610,50 @@ void ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const cha ea = NULL; \ } while(0) \ +struct ea_one_attr_list { + ea_list l; + eattr a; +}; + static inline eattr * ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, uintptr_t val) { - ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr)); - eattr *e = &a->attrs[0]; + struct ea_one_attr_list *ea = lp_alloc(pool, sizeof(*ea)); + *ea = (struct ea_one_attr_list) { + .l.flags = EALF_SORTED, + .l.count = 1, + .l.next = *to, - a->flags = EALF_SORTED; - a->count = 1; - a->next = *to; - *to = a; - - e->id = id; - e->type = type; - e->flags = flags; + .a.id = id, + .a.type = type, + .a.flags = flags, + }; if (type & EAF_EMBEDDED) - e->u.data = (u32) val; + ea->a.u.data = val; else - e->u.ptr = (struct adata *) val; + ea->a.u.ptr = (struct adata *) val; + + *to = &ea->l; - return e; + return &ea->a; +} + +static inline void +ea_unset_attr(ea_list **to, struct linpool *pool, _Bool local, uint code) +{ + struct ea_one_attr_list *ea = lp_alloc(pool, sizeof(*ea)); + *ea = (struct ea_one_attr_list) { + .l.flags = EALF_SORTED, + .l.count = 1, + .l.next = *to, + .a.id = code, + .a.fresh = local, + .a.originated = local, + .a.undef = 1, + }; + + *to = &ea->l; } static inline void @@ -718,7 +691,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..22b45db9 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", @@ -155,7 +154,7 @@ rt_prune_sources(void) { HASH_DO_REMOVE(src_hash, RSH, sp); idm_free(&src_ids, src->global_id); - sl_free(rte_src_slab, src); + sl_free(src); } } HASH_WALK_FILTER_END; @@ -392,7 +391,7 @@ nexthop_free(struct nexthop *o) while (o) { n = o->next; - sl_free(nexthop_slab(o), o); + sl_free(o); o = n; } } @@ -449,8 +448,7 @@ ea_find(ea_list *e, unsigned id) { eattr *a = ea__find(e, id & EA_CODE_MASK); - if (a && (a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF && - !(id & EA_ALLOW_UNDEF)) + if (a && a->undef && !(id & EA_ALLOW_UNDEF)) return NULL; return a; } @@ -517,7 +515,7 @@ ea_walk(struct ea_walk_state *s, uint id, uint max) BIT32_SET(s->visited, n); - if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF) + if (a->undef) continue; s->eattrs = e; @@ -541,8 +539,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) @@ -617,14 +615,17 @@ ea_do_prune(ea_list *e) /* Now s0 is the most recent version, s[-1] the oldest one */ /* Drop undefs */ - if ((s0->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF) + if (s0->undef) continue; /* Copy the newest version to destination */ *d = *s0; /* Preserve info whether it originated locally */ - d->type = (d->type & ~(EAF_ORIGINATED|EAF_FRESH)) | (s[-1].type & EAF_ORIGINATED); + d->originated = s[-1].originated; + + /* Not fresh any more, we prefer surstroemming */ + d->fresh = 0; /* Next destination */ d++; @@ -738,6 +739,9 @@ ea_same(ea_list *x, ea_list *y) if (a->id != b->id || a->flags != b->flags || a->type != b->type || + a->originated != b->originated || + a->fresh != b->fresh || + a->undef != b->undef || ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr))) return 0; } @@ -940,6 +944,10 @@ ea_show(struct cli *c, const eattr *e) { *pos++ = ':'; *pos++ = ' '; + + if (e->undef) + bsprintf(pos, "undefined"); + else switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: @@ -969,7 +977,6 @@ ea_show(struct cli *c, const eattr *e) case EAF_TYPE_LC_SET: ea_show_lc_set(c, ad, pos, buf, end); return; - case EAF_TYPE_UNDEF: default: bsprintf(pos, "<type %02x>", e->type); } @@ -1005,7 +1012,7 @@ ea_dump(ea_list *e) eattr *a = &e->attrs[i]; debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags); debug("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]); - if (a->type & EAF_ORIGINATED) + if (a->originated) debug("o"); if (a->type & EAF_EMBEDDED) debug(":%08x", a->u.data); @@ -1104,13 +1111,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 +1127,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 +1205,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 +1216,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,18 +1229,17 @@ 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 */ - sl_free(rta_slab(a), a); + a->cached = 0; + sl_free(a); } rta * @@ -1248,7 +1253,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 +1267,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..05e64fc3 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); } @@ -195,3 +195,9 @@ struct protocol proto_device = { .reconfigure = dev_reconfigure, .copy_config = dev_copy_config }; + +void +dev_build(void) +{ + proto_build(&proto_device); +} diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 1690a8f6..43e3039d 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -475,7 +475,7 @@ fib_delete(struct fib *f, void *E) } if (f->fib_slab) - sl_free(f->fib_slab, E); + sl_free(E); else mb_free(E); 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 c3563171..82db879e 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(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(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"); } @@ -2299,12 +2094,7 @@ static struct resclass rt_class = { rtable * rt_setup(pool *pp, struct rtable_config *cf) { - int ns = strlen("Routing table ") + strlen(cf->name) + 1; - void *nb = mb_alloc(pp, ns); - ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name)); - - pool *p = rp_new(pp, nb); - mb_move(nb, p); + pool *p = rp_newf(pp, "Routing table %s", cf->name); rtable *t = ralloc(p, &rt_class); t->rp = p; @@ -2716,11 +2506,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 +2635,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 +2653,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 +2693,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 +3027,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 +3040,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 +3145,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 +3218,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 +3228,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 +3236,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 +3244,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 +3262,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; @@ -3603,7 +3393,7 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he) rem_node(&he->ln); hc_remove(hc, he); - sl_free(hc->slab, he); + sl_free(he); hc->hash_items--; if (hc->hash_items < hc->hash_min) @@ -3620,7 +3410,7 @@ rt_init_hostcache(rtable *tab) hc_alloc_table(hc, tab->rp, HC_DEF_ORDER); hc->slab = sl_new(tab->rp, sizeof(struct hostentry)); - hc->lp = lp_new(tab->rp, LP_GOOD_SIZE(1024)); + hc->lp = lp_new(tab->rp); hc->trie = f_new_trie(hc->lp, 0); tab->hostcache = hc; @@ -3679,36 +3469,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; } |