mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Merge commit 'fb7fb674' into HEAD
This commit is contained in:
commit
f69ba3921a
@ -27,7 +27,7 @@ struct config {
|
||||
|
||||
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
|
||||
const char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
|
||||
struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
|
||||
struct symbol *def_tables[NET_MAX]; /* Default routing tables for each network */
|
||||
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
|
||||
|
||||
u32 router_id; /* Our Router ID */
|
||||
|
@ -505,6 +505,11 @@ include "tablename.conf";;
|
||||
See <ref id="channel-debug" name="debug"> in the channel section.
|
||||
Default: off.
|
||||
|
||||
<tag><label id="opt-debug-tables">debug tables all|off|{ states|routes|filters|events [, <m/.../] }</tag>
|
||||
Set global defaults of table debugging options.
|
||||
See <ref id="rtable-debug" name="debug"> in the table section.
|
||||
Default: off.
|
||||
|
||||
<tag><label id="opt-debug-commands">debug commands <m/number/</tag>
|
||||
Control logging of client connections (0 for no logging, 1 for logging
|
||||
of connects and disconnects, 2 and higher for logging of all client
|
||||
@ -670,21 +675,6 @@ to set options.
|
||||
disadvantage is that trie-enabled routing tables require more memory,
|
||||
which may be an issue especially in multi-table setups. Default: off.
|
||||
|
||||
<tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
|
||||
Specify a minimum value of the settle time. When a ROA table changes,
|
||||
automatic <ref id="proto-rpki-reload" name="RPKI reload"> may be
|
||||
triggered, after a short settle time. Minimum settle time is a delay
|
||||
from the last ROA table change to wait for more updates. Default: 1 s.
|
||||
|
||||
|
||||
<tag><label id="rtable-max-settle-time">max settle time <m/time/</tag>
|
||||
Specify a maximum value of the settle time. When a ROA table changes,
|
||||
automatic <ref id="proto-rpki-reload" name="RPKI reload"> may be
|
||||
triggered, after a short settle time. Maximum settle time is an upper
|
||||
limit to the settle time from the initial ROA table change even if
|
||||
there are consecutive updates gradually renewing the settle time.
|
||||
Default: 20 s.
|
||||
|
||||
<tag><label id="rtable-gc-threshold">gc threshold <m/number/</tag>
|
||||
Specify a minimum amount of removed networks that triggers a garbage
|
||||
collection (GC) cycle. Default: 1000.
|
||||
@ -708,6 +698,16 @@ to set options.
|
||||
second one is the high threshold (when to pause). The higher is the
|
||||
threshold, the more memory can get used. In most cases, the defaults
|
||||
should work for you. Default: 128, 512.
|
||||
|
||||
<tag><label id="rtable-debug">debug all|off|{ states|routes|events [, <m/.../] }</tag>
|
||||
Set table debugging options. Each table can write some trace messages
|
||||
into log with category <cf/trace/. You can request <cf/all/ trace messages
|
||||
or select some types: <cf/states/ for table state changes and auxiliary
|
||||
processes, <cf/routes/ for auxiliary route notifications (next hop update,
|
||||
flowspec revalidation) and <cf/events/ for more detailed auxiliary routine
|
||||
debug. See also <ref id="channel-debug" name="channel debugging option">.
|
||||
Default: off.
|
||||
|
||||
</descrip>
|
||||
|
||||
|
||||
@ -965,6 +965,15 @@ inherited from templates can be updated by new definitions.
|
||||
<ref id="bgp-export-table" name="export table"> (for respective
|
||||
direction). Default: on.
|
||||
|
||||
<tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
|
||||
Minimum settle time is a delay from the last ROA table change to wait
|
||||
for more updates before triggering automatic reload. Default: 1 s.
|
||||
|
||||
<tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
|
||||
Maximum settle time is an upper limit to the settle time from the
|
||||
initial ROA table change even if there are consecutive updates gradually
|
||||
renewing the settle time. Default: 20 s.
|
||||
|
||||
<tag><label id="proto-import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
|
||||
Specify an import route limit (a maximum number of routes imported from
|
||||
the protocol) and optionally the action to be taken when the limit is
|
||||
|
@ -1467,7 +1467,7 @@
|
||||
ARG(1, T_NET);
|
||||
ARG(2, T_INT);
|
||||
RTC(3);
|
||||
struct rtable *table = rtc->table;
|
||||
rtable *table = rtc->table;
|
||||
|
||||
u32 as = v2.val.i;
|
||||
|
||||
|
@ -14,8 +14,9 @@
|
||||
|
||||
/* Ugly structure offset handling macros */
|
||||
|
||||
#define SAME_TYPE(a, b) ({ int _ = ((a) != (b)); !_; })
|
||||
#define OFFSETOF(s, i) ((size_t) &((s *)0)->i)
|
||||
#define SKIP_BACK(s, i, p) ({ s *_ptr = ((s *)((char *)p - OFFSETOF(s, i))); ASSERT_DIE(&_ptr->i == p); _ptr; })
|
||||
#define SKIP_BACK(s, i, p) ({ s *_ptr = ((s *)((char *)p - OFFSETOF(s, i))); SAME_TYPE(&_ptr->i, p); _ptr; })
|
||||
#define BIRD_ALIGN(s, a) (((s)+a-1)&~(a-1))
|
||||
#define CPU_STRUCT_ALIGN (MAX_(_Alignof(void*), _Alignof(u64)))
|
||||
#define BIRD_CPU_ALIGN(s) BIRD_ALIGN((s), CPU_STRUCT_ALIGN)
|
||||
|
@ -20,7 +20,7 @@
|
||||
struct network;
|
||||
struct proto;
|
||||
struct cli;
|
||||
struct rtable;
|
||||
struct rtable_private;
|
||||
|
||||
typedef struct rte {
|
||||
struct ea_list *attrs; /* Attributes of this route */
|
||||
@ -63,7 +63,7 @@ struct rte_owner_class {
|
||||
|
||||
struct rte_owner {
|
||||
struct rte_owner_class *class;
|
||||
int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
|
||||
int (*rte_recalculate)(struct rtable_private *, struct network *, struct rte *, struct rte *, struct rte *);
|
||||
HASH(struct rte_src) hash;
|
||||
const char *name;
|
||||
u32 hash_key;
|
||||
|
@ -227,14 +227,13 @@ table_opt:
|
||||
cf_error("Trie option not supported for %s table", net_label[this_table->addr_type]);
|
||||
this_table->trie_used = $2;
|
||||
}
|
||||
| MIN SETTLE TIME expr_us { this_table->min_settle_time = $4; }
|
||||
| MAX SETTLE TIME expr_us { this_table->max_settle_time = $4; }
|
||||
| GC THRESHOLD expr { this_table->gc_threshold = $3; }
|
||||
| GC PERIOD expr_us { this_table->gc_period = (uint) $3; if ($3 > 3600 S_) cf_error("GC period must be at most 3600 s"); }
|
||||
| CORK THRESHOLD expr expr {
|
||||
if ($3 > $4) cf_error("Cork low threshold must be lower than the high threshold.");
|
||||
this_table->cork_threshold.low = $3;
|
||||
this_table->cork_threshold.high = $4; }
|
||||
| DEBUG bool { this_table->debug = $2; }
|
||||
;
|
||||
|
||||
table_opts:
|
||||
@ -322,6 +321,8 @@ channel_item_:
|
||||
| RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
|
||||
| IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
|
||||
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
|
||||
| MIN SETTLE TIME expr_us { this_channel->min_settle_time = $4; }
|
||||
| MAX SETTLE TIME expr_us { this_channel->max_settle_time = $4; }
|
||||
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
|
||||
| IMPORT KEEP FILTERED bool {
|
||||
if ($4)
|
||||
@ -361,7 +362,11 @@ channel_end:
|
||||
proto_channel: channel_start channel_opt_list channel_end;
|
||||
|
||||
|
||||
rtable: CF_SYM_KNOWN { cf_assert_symbol($1, SYM_TABLE); $$ = $1->table; } ;
|
||||
rtable: CF_SYM_KNOWN {
|
||||
cf_assert_symbol($1, SYM_TABLE);
|
||||
if (!$1->table) rt_new_default_table($1);
|
||||
$$ = $1->table;
|
||||
} ;
|
||||
|
||||
imexport:
|
||||
FILTER filter { $$ = $2; }
|
||||
@ -390,7 +395,7 @@ debug_default:
|
||||
DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
|
||||
| DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; }
|
||||
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
|
||||
| DEBUG TABLES bool { new_config->table_debug = $3; }
|
||||
| DEBUG TABLES debug_mask { new_config->table_debug = $3; }
|
||||
;
|
||||
|
||||
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
|
||||
@ -683,6 +688,7 @@ r_args:
|
||||
}
|
||||
| r_args TABLE symbol_known {
|
||||
cf_assert_symbol($3, SYM_TABLE);
|
||||
if (!$3->table) cf_error("Table %s not configured", $3->name);
|
||||
$$ = $1;
|
||||
rt_show_add_table($$, $3->table->table);
|
||||
$$->tables_defined_by = RSD_TDB_DIRECT;
|
||||
@ -696,7 +702,8 @@ r_args:
|
||||
}
|
||||
| r_args IMPORT TABLE channel_arg {
|
||||
if (!($4->in_keep & RIK_PREFILTER)) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name);
|
||||
rt_show_add_exporter($$, &$4->table->exporter, "import")->prefilter = $4;
|
||||
RT_LOCKED($4->table, tab)
|
||||
rt_show_add_exporter($$, &tab->exporter.e, "import")->prefilter = $4;
|
||||
$$->tables_defined_by = RSD_TDB_DIRECT;
|
||||
}
|
||||
| r_args EXPORT TABLE channel_arg {
|
||||
|
146
nest/proto.c
146
nest/proto.c
@ -55,6 +55,7 @@ static void channel_update_limit(struct channel *c, struct limit *l, int dir, st
|
||||
static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
|
||||
static void channel_feed_end(struct channel *c);
|
||||
static void channel_export_stopped(struct rt_export_request *req);
|
||||
static void channel_check_stopped(struct channel *c);
|
||||
|
||||
static inline int proto_is_done(struct proto *p)
|
||||
{ return (p->proto_state == PS_DOWN) && proto_is_inactive(p); }
|
||||
@ -168,7 +169,7 @@ proto_cf_find_channel(struct proto_config *pc, uint net_type)
|
||||
* Returns pointer to channel or NULL
|
||||
*/
|
||||
struct channel *
|
||||
proto_find_channel_by_table(struct proto *p, struct rtable *t)
|
||||
proto_find_channel_by_table(struct proto *p, rtable *t)
|
||||
{
|
||||
struct channel *c;
|
||||
|
||||
@ -312,10 +313,19 @@ proto_remove_channels(struct proto *p)
|
||||
proto_remove_channel(p, c);
|
||||
}
|
||||
|
||||
struct roa_subscription {
|
||||
node roa_node;
|
||||
timer t;
|
||||
btime base_settle_time; /* Start of settling interval */
|
||||
struct channel *c;
|
||||
struct rt_export_request req;
|
||||
};
|
||||
|
||||
static void
|
||||
channel_roa_in_changed(void *_data)
|
||||
channel_roa_in_changed(struct timer *t)
|
||||
{
|
||||
struct channel *c = _data;
|
||||
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
|
||||
struct channel *c = s->c;
|
||||
int active = !!c->reload_req.hook;
|
||||
|
||||
CD(c, "Reload triggered by RPKI change%s", active ? " - already active" : "");
|
||||
@ -327,9 +337,11 @@ channel_roa_in_changed(void *_data)
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_out_changed(void *_data)
|
||||
channel_roa_out_changed(struct timer *t)
|
||||
{
|
||||
struct channel *c = _data;
|
||||
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, t, t);
|
||||
struct channel *c = s->c;
|
||||
|
||||
CD(c, "Feeding triggered by RPKI change");
|
||||
|
||||
c->refeed_pending = 1;
|
||||
@ -338,29 +350,57 @@ channel_roa_out_changed(void *_data)
|
||||
rt_stop_export(&c->out_req, channel_export_stopped);
|
||||
}
|
||||
|
||||
/* Temporary code, subscriptions should be changed to resources */
|
||||
struct roa_subscription {
|
||||
struct rt_subscription s;
|
||||
node roa_node;
|
||||
};
|
||||
static void
|
||||
channel_export_one_roa(struct rt_export_request *req, const net_addr *net UNUSED, struct rt_pending_export *first)
|
||||
{
|
||||
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
|
||||
|
||||
/* TODO: use the information about what roa has changed */
|
||||
|
||||
if (!tm_active(&s->t))
|
||||
{
|
||||
s->base_settle_time = current_time();
|
||||
tm_start(&s->t, s->base_settle_time + s->c->min_settle_time);
|
||||
}
|
||||
else
|
||||
tm_set(&s->t,
|
||||
MIN(s->base_settle_time + s->c->max_settle_time,
|
||||
current_time() + s->c->min_settle_time));
|
||||
|
||||
|
||||
rpe_mark_seen_all(req->hook, first, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_dump_roa_req(struct rt_export_request *req)
|
||||
{
|
||||
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
|
||||
struct channel *c = s->c;
|
||||
struct rtable_private *tab = SKIP_BACK(struct rtable_private, exporter.e, req->hook->table);
|
||||
|
||||
debug(" Channel %s.%s ROA %s change notifier from table %s request %p\n",
|
||||
c->proto->name, c->name,
|
||||
(s->t.hook == channel_roa_in_changed) ? "import" : "export",
|
||||
tab->name, req);
|
||||
}
|
||||
|
||||
static int
|
||||
channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
|
||||
{
|
||||
void (*hook)(void *) =
|
||||
void (*hook)(struct timer *) =
|
||||
dir ? channel_roa_in_changed : channel_roa_out_changed;
|
||||
|
||||
struct roa_subscription *s;
|
||||
node *n;
|
||||
|
||||
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
|
||||
if ((s->s.tab == tab) && (s->s.event->hook == hook))
|
||||
if ((tab == SKIP_BACK(rtable, priv.exporter.e, s->req.hook->table))
|
||||
&& (s->t.hook == hook))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
|
||||
{
|
||||
@ -368,28 +408,47 @@ channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
|
||||
return;
|
||||
|
||||
struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
|
||||
s->s.event = ev_new_init(c->proto->pool, dir ? channel_roa_in_changed : channel_roa_out_changed, c);
|
||||
s->s.list = proto_work_list(c->proto);
|
||||
|
||||
rt_subscribe(tab, &s->s);
|
||||
*s = (struct roa_subscription) {
|
||||
.t = { .hook = dir ? channel_roa_in_changed : channel_roa_out_changed, },
|
||||
.c = c,
|
||||
.req = {
|
||||
.name = mb_sprintf(c->proto->pool, "%s.%s.roa-%s.%s",
|
||||
c->proto->name, c->name, dir ? "in" : "out", tab->name),
|
||||
.list = proto_work_list(c->proto),
|
||||
.trace_routes = c->debug | c->proto->debug,
|
||||
.dump_req = channel_dump_roa_req,
|
||||
.export_one = channel_export_one_roa,
|
||||
},
|
||||
};
|
||||
|
||||
add_tail(&c->roa_subscriptions, &s->roa_node);
|
||||
rt_request_export(tab, &s->req);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_unsubscribed(struct rt_export_request *req)
|
||||
{
|
||||
struct roa_subscription *s = SKIP_BACK(struct roa_subscription, req, req);
|
||||
struct channel *c = s->c;
|
||||
|
||||
rem_node(&s->roa_node);
|
||||
mb_free(s);
|
||||
|
||||
channel_check_stopped(c);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_unsubscribe(struct roa_subscription *s)
|
||||
{
|
||||
rt_unsubscribe(&s->s);
|
||||
rem_node(&s->roa_node);
|
||||
rfree(s->s.event);
|
||||
mb_free(s);
|
||||
rt_stop_export(&s->req, channel_roa_unsubscribed);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_subscribe_filter(struct channel *c, int dir)
|
||||
{
|
||||
const struct filter *f = dir ? c->in_filter : c->out_filter;
|
||||
struct rtable *tab;
|
||||
rtable *tab;
|
||||
int valid = 1, found = 0;
|
||||
|
||||
if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT))
|
||||
@ -450,13 +509,10 @@ channel_start_import(struct channel *c)
|
||||
return;
|
||||
}
|
||||
|
||||
int nlen = strlen(c->name) + strlen(c->proto->name) + 2;
|
||||
char *rn = mb_allocz(c->proto->pool, nlen);
|
||||
bsprintf(rn, "%s.%s", c->proto->name, c->name);
|
||||
|
||||
c->in_req = (struct rt_import_request) {
|
||||
.name = rn,
|
||||
.name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
|
||||
.trace_routes = c->debug | c->proto->debug,
|
||||
.list = proto_work_list(c->proto),
|
||||
.dump_req = channel_dump_import_req,
|
||||
.log_state_change = channel_import_log_state_change,
|
||||
.preimport = channel_preimport,
|
||||
@ -483,12 +539,9 @@ channel_start_export(struct channel *c)
|
||||
}
|
||||
|
||||
ASSERT(c->channel_state == CS_UP);
|
||||
int nlen = strlen(c->name) + strlen(c->proto->name) + 2;
|
||||
char *rn = mb_allocz(c->proto->pool, nlen);
|
||||
bsprintf(rn, "%s.%s", c->proto->name, c->name);
|
||||
|
||||
c->out_req = (struct rt_export_request) {
|
||||
.name = rn,
|
||||
.name = mb_sprintf(c->proto->pool, "%s.%s", c->proto->name, c->name),
|
||||
.list = proto_work_list(c->proto),
|
||||
.addr = c->out_subprefix,
|
||||
.addr_mode = c->out_subprefix ? TE_ADDR_IN : TE_ADDR_NONE,
|
||||
@ -523,7 +576,7 @@ channel_start_export(struct channel *c)
|
||||
}
|
||||
|
||||
DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req);
|
||||
rt_request_export(&c->table->exporter, &c->out_req);
|
||||
rt_request_export(c->table, &c->out_req);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -532,7 +585,7 @@ channel_check_stopped(struct channel *c)
|
||||
switch (c->channel_state)
|
||||
{
|
||||
case CS_STOP:
|
||||
if (c->out_req.hook || c->in_req.hook)
|
||||
if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->in_req.hook)
|
||||
return;
|
||||
|
||||
channel_set_state(c, CS_DOWN);
|
||||
@ -540,7 +593,7 @@ channel_check_stopped(struct channel *c)
|
||||
|
||||
break;
|
||||
case CS_PAUSE:
|
||||
if (c->out_req.hook)
|
||||
if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook)
|
||||
return;
|
||||
|
||||
channel_set_state(c, CS_START);
|
||||
@ -557,8 +610,6 @@ channel_import_stopped(struct rt_import_request *req)
|
||||
{
|
||||
struct channel *c = SKIP_BACK(struct channel, in_req, req);
|
||||
|
||||
req->hook = NULL;
|
||||
|
||||
mb_free(c->in_req.name);
|
||||
c->in_req.name = NULL;
|
||||
|
||||
@ -577,7 +628,7 @@ channel_export_stopped(struct rt_export_request *req)
|
||||
{
|
||||
c->refeeding = 1;
|
||||
c->refeed_pending = 0;
|
||||
rt_request_export(&c->table->exporter, req);
|
||||
rt_request_export(c->table, req);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -621,7 +672,7 @@ channel_schedule_reload(struct channel *c)
|
||||
{
|
||||
ASSERT(c->in_req.hook);
|
||||
|
||||
rt_request_export(&c->table->exporter, &c->reload_req);
|
||||
rt_request_export(c->table, &c->reload_req);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -864,7 +915,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
|
||||
if (proto->net_type && (net_type != proto->net_type))
|
||||
cf_error("Different channel type");
|
||||
|
||||
tab = new_config->def_tables[net_type];
|
||||
tab = rt_get_default_table(new_config, net_type);
|
||||
}
|
||||
|
||||
if (!cc)
|
||||
@ -883,6 +934,9 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
|
||||
cf->debug = new_config->channel_default_debug;
|
||||
cf->rpki_reload = 1;
|
||||
|
||||
cf->min_settle_time = 1 S;
|
||||
cf->max_settle_time = 20 S;
|
||||
|
||||
add_tail(&proto->channels, &cf->n);
|
||||
|
||||
return cf;
|
||||
@ -963,6 +1017,22 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||
c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug;
|
||||
c->rpki_reload = cf->rpki_reload;
|
||||
|
||||
if ( (c->min_settle_time != cf->min_settle_time)
|
||||
|| (c->max_settle_time != cf->max_settle_time))
|
||||
{
|
||||
c->min_settle_time = cf->min_settle_time;
|
||||
c->max_settle_time = cf->max_settle_time;
|
||||
|
||||
struct roa_subscription *s;
|
||||
node *n;
|
||||
|
||||
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
|
||||
if (tm_active(&s->t))
|
||||
tm_set(&s->t,
|
||||
MIN(s->base_settle_time + c->max_settle_time,
|
||||
current_time() + c->min_settle_time));
|
||||
}
|
||||
|
||||
/* Execute channel-specific reconfigure hook */
|
||||
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
|
||||
return 0;
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
struct iface;
|
||||
struct ifa;
|
||||
struct rtable;
|
||||
struct rte;
|
||||
struct neighbor;
|
||||
struct rta;
|
||||
@ -187,7 +186,7 @@ struct proto {
|
||||
* rte_remove Called whenever a rte is removed from the routing table.
|
||||
*/
|
||||
|
||||
int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *);
|
||||
int (*rte_recalculate)(struct rtable_private *, struct network *, struct rte *, struct rte *, struct rte *);
|
||||
int (*rte_mergable)(struct rte *, struct rte *);
|
||||
void (*rte_insert)(struct network *, struct rte *);
|
||||
void (*rte_remove)(struct network *, struct rte *);
|
||||
@ -460,6 +459,9 @@ struct channel_config {
|
||||
struct channel_limit in_limit; /* Limit for importing routes from protocol */
|
||||
struct channel_limit out_limit; /* Limit for exporting routes to protocol */
|
||||
|
||||
btime min_settle_time; /* Minimum settle time for ROA-induced reload */
|
||||
btime max_settle_time; /* Maximum settle time for ROA-induced reload */
|
||||
|
||||
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
|
||||
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
|
||||
u16 preference; /* Default route preference */
|
||||
@ -476,7 +478,7 @@ struct channel {
|
||||
const struct channel_class *channel;
|
||||
struct proto *proto;
|
||||
|
||||
struct rtable *table;
|
||||
rtable *table;
|
||||
const struct filter *in_filter; /* Input filter */
|
||||
const struct filter *out_filter; /* Output filter */
|
||||
const net_addr *out_subprefix; /* Export only subprefixes of this net */
|
||||
@ -487,6 +489,9 @@ struct channel {
|
||||
struct limit in_limit; /* Input limit */
|
||||
struct limit out_limit; /* Output limit */
|
||||
|
||||
btime min_settle_time; /* Minimum settle time for ROA-induced reload */
|
||||
btime max_settle_time; /* Maximum settle time for ROA-induced reload */
|
||||
|
||||
u8 limit_actions[PLD_MAX]; /* Limit actions enum */
|
||||
u8 limit_active; /* Flags for active limits */
|
||||
|
||||
@ -540,7 +545,7 @@ struct channel {
|
||||
|
||||
struct rt_exporter *out_table; /* Internal table for exported routes */
|
||||
|
||||
list roa_subscriptions; /* List of active ROA table subscriptions based on filters roa_check() */
|
||||
list roa_subscriptions; /* List of active ROA table subscriptions based on filters' roa_check() calls */
|
||||
};
|
||||
|
||||
#define RIK_REJECTED 1 /* Routes rejected in import filter are kept */
|
||||
@ -604,7 +609,7 @@ struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_ty
|
||||
static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
|
||||
{ return proto_cf_find_channel(pc, pc->net_type); }
|
||||
|
||||
struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t);
|
||||
struct channel *proto_find_channel_by_table(struct proto *p, rtable *t);
|
||||
struct channel *proto_find_channel_by_name(struct proto *p, const char *n);
|
||||
struct channel *proto_add_channel(struct proto *p, struct channel_config *cf);
|
||||
int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf);
|
||||
|
@ -301,7 +301,7 @@ rt_show_cont(struct rt_show_data *d)
|
||||
if (d->tables_defined_by & RSD_TDB_SET)
|
||||
rt_show_table(d);
|
||||
|
||||
rt_request_export(d->tab->table, &d->req);
|
||||
rt_request_export_other(d->tab->table, &d->req);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -354,9 +354,11 @@ rt_show_add_exporter(struct rt_show_data *d, struct rt_exporter *t, const char *
|
||||
}
|
||||
|
||||
struct rt_show_data_rtable *
|
||||
rt_show_add_table(struct rt_show_data *d, struct rtable *t)
|
||||
rt_show_add_table(struct rt_show_data *d, rtable *t)
|
||||
{
|
||||
struct rt_show_data_rtable *rsdr = rt_show_add_exporter(d, &t->exporter, t->name);
|
||||
struct rt_show_data_rtable *rsdr;
|
||||
RT_LOCKED(t, tp)
|
||||
rsdr = rt_show_add_exporter(d, &tp->exporter.e, t->name);
|
||||
|
||||
struct proto_config *krt = t->config->krt_attached;
|
||||
if (krt)
|
||||
@ -400,8 +402,8 @@ rt_show_get_default_tables(struct rt_show_data *d)
|
||||
}
|
||||
|
||||
for (int i=1; i<NET_MAX; i++)
|
||||
if (config->def_tables[i] && config->def_tables[i]->table)
|
||||
rt_show_add_table(d, config->def_tables[i]->table);
|
||||
if (config->def_tables[i] && config->def_tables[i]->table && config->def_tables[i]->table->table)
|
||||
rt_show_add_table(d, config->def_tables[i]->table->table);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -418,12 +420,13 @@ rt_show_prepare_tables(struct rt_show_data *d)
|
||||
/* Ensure there is defined export_channel for each table */
|
||||
if (d->export_mode)
|
||||
{
|
||||
rtable *rt = SKIP_BACK(rtable, priv.exporter.e, tab->table);
|
||||
if (!tab->export_channel && d->export_channel &&
|
||||
(tab->table == &d->export_channel->table->exporter))
|
||||
(rt == d->export_channel->table))
|
||||
tab->export_channel = d->export_channel;
|
||||
|
||||
if (!tab->export_channel && d->export_protocol)
|
||||
tab->export_channel = proto_find_channel_by_table(d->export_protocol, SKIP_BACK(rtable, exporter, tab->table));
|
||||
tab->export_channel = proto_find_channel_by_table(d->export_protocol, rt);
|
||||
|
||||
if (!tab->export_channel)
|
||||
{
|
||||
|
1710
nest/rt-table.c
1710
nest/rt-table.c
File diff suppressed because it is too large
Load Diff
264
nest/rt.h
264
nest/rt.h
@ -27,6 +27,7 @@ struct protocol;
|
||||
struct proto;
|
||||
struct channel;
|
||||
struct rte_src;
|
||||
struct hostcache;
|
||||
struct symbol;
|
||||
struct timer;
|
||||
struct filter;
|
||||
@ -52,31 +53,37 @@ struct rt_cork_threshold {
|
||||
struct rtable_config {
|
||||
node n;
|
||||
char *name;
|
||||
struct rtable *table;
|
||||
union rtable *table;
|
||||
struct proto_config *krt_attached; /* Kernel syncer attached to this table */
|
||||
uint addr_type; /* Type of address data stored in table (NET_*) */
|
||||
uint gc_threshold; /* Maximum number of operations before GC is run */
|
||||
uint gc_period; /* Approximate time between two consecutive GC runs */
|
||||
byte sorted; /* Routes of network are sorted according to rte_better() */
|
||||
byte trie_used; /* Rtable has attached trie */
|
||||
btime min_settle_time; /* Minimum settle time for notifications */
|
||||
btime max_settle_time; /* Maximum settle time for notifications */
|
||||
byte debug; /* Whether to log */
|
||||
btime export_settle_time; /* Delay before exports are announced */
|
||||
struct rt_cork_threshold cork_threshold; /* Cork threshold values */
|
||||
};
|
||||
|
||||
struct rt_export_hook;
|
||||
struct rt_export_request;
|
||||
struct rt_exporter;
|
||||
|
||||
struct rt_exporter_class {
|
||||
void (*start)(struct rt_exporter *, struct rt_export_request *);
|
||||
void (*stop)(struct rt_export_hook *);
|
||||
void (*done)(void *_rt_export_hook);
|
||||
};
|
||||
|
||||
struct rt_exporter {
|
||||
const struct rt_exporter_class *class;
|
||||
pool *rp;
|
||||
list hooks; /* Registered route export hooks */
|
||||
uint addr_type; /* Type of address data exported (NET_*) */
|
||||
};
|
||||
|
||||
struct rt_export_hook *(*start)(struct rt_exporter *, struct rt_export_request *);
|
||||
void (*stop)(struct rt_export_hook *);
|
||||
void (*done)(struct rt_export_hook *);
|
||||
void (*used)(struct rt_exporter *);
|
||||
|
||||
struct rt_table_exporter {
|
||||
struct rt_exporter e;
|
||||
list pending; /* List of packed struct rt_pending_export */
|
||||
struct timer *export_timer;
|
||||
|
||||
@ -84,39 +91,50 @@ struct rt_exporter {
|
||||
u64 next_seq; /* The next export will have this ID */
|
||||
};
|
||||
|
||||
typedef struct rtable {
|
||||
resource r;
|
||||
node n; /* Node in list of all tables */
|
||||
extern uint rtable_max_id;
|
||||
|
||||
DEFINE_DOMAIN(rtable);
|
||||
|
||||
/* The public part of rtable structure */
|
||||
#define RTABLE_PUBLIC \
|
||||
resource r; \
|
||||
node n; /* Node in list of all tables */ \
|
||||
char *name; /* Name of this table */ \
|
||||
uint addr_type; /* Type of address data stored in table (NET_*) */ \
|
||||
uint id; /* Integer table ID for fast lookup */ \
|
||||
DOMAIN(rtable) lock; /* Lock to take to access the private parts */ \
|
||||
struct rtable_config *config; /* Configuration of this table */ \
|
||||
|
||||
/* The complete rtable structure */
|
||||
struct rtable_private {
|
||||
/* Once more the public part */
|
||||
RTABLE_PUBLIC;
|
||||
|
||||
/* Here the private items not to be accessed without locking */
|
||||
pool *rp; /* Resource pool to allocate everything from, including itself */
|
||||
struct slab *rte_slab; /* Slab to allocate route objects */
|
||||
struct fib fib;
|
||||
struct f_trie *trie; /* Trie of prefixes defined in fib */
|
||||
char *name; /* Name of this table */
|
||||
uint addr_type; /* Type of address data stored in table (NET_*) */
|
||||
int use_count; /* Number of protocols using this table */
|
||||
u32 rt_count; /* Number of routes in the table */
|
||||
|
||||
list imports; /* Registered route importers */
|
||||
struct rt_exporter exporter; /* Exporter API structure */
|
||||
struct rt_table_exporter exporter; /* Exporter API structure */
|
||||
|
||||
struct hmap id_map;
|
||||
struct hostcache *hostcache;
|
||||
struct rtable_config *config; /* Configuration of this table */
|
||||
struct config *deleted; /* Table doesn't exist in current configuration,
|
||||
* delete as soon as use_count becomes 0 and remove
|
||||
* obstacle from this routing table.
|
||||
*/
|
||||
struct event *rt_event; /* Routing table event */
|
||||
struct event *uncork_event; /* Called when uncork happens */
|
||||
struct event *nhu_event; /* Specific event for next hop update */
|
||||
struct timer *prune_timer; /* Timer for periodic pruning / GC */
|
||||
btime last_rt_change; /* Last time when route changed */
|
||||
btime base_settle_time; /* Start time of rtable settling interval */
|
||||
btime gc_time; /* Time of last GC */
|
||||
uint gc_counter; /* Number of operations since last GC */
|
||||
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
|
||||
byte prune_trie; /* Prune prefix trie during next table prune */
|
||||
byte hcu_scheduled; /* Hostcache update is scheduled */
|
||||
byte hcu_corked; /* Hostcache update is corked with this state */
|
||||
byte nhu_state; /* Next Hop Update state */
|
||||
byte nhu_corked; /* Next Hop Update is corked with this state */
|
||||
byte export_used; /* Pending Export pruning is scheduled */
|
||||
@ -130,25 +148,28 @@ typedef struct rtable {
|
||||
u32 trie_old_lock_count; /* Old prefix trie locked by walks */
|
||||
struct tbf rl_pipe; /* Rate limiting token buffer for pipe collisions */
|
||||
|
||||
list subscribers; /* Subscribers for notifications */
|
||||
struct timer *settle_timer; /* Settle time for notifications */
|
||||
list flowspec_links; /* List of flowspec links, src for NET_IPx and dst for NET_FLOWx */
|
||||
struct f_trie *flowspec_trie; /* Trie for evaluation of flowspec notifications */
|
||||
};
|
||||
|
||||
/* The final union private-public rtable structure */
|
||||
typedef union rtable {
|
||||
struct {
|
||||
RTABLE_PUBLIC;
|
||||
};
|
||||
struct rtable_private priv;
|
||||
} rtable;
|
||||
|
||||
struct rt_subscription {
|
||||
node n;
|
||||
rtable *tab;
|
||||
event *event;
|
||||
event_list *list;
|
||||
};
|
||||
#define RT_IS_LOCKED(tab) DOMAIN_IS_LOCKED(rtable, (tab)->lock)
|
||||
|
||||
struct rt_flowspec_link {
|
||||
node n;
|
||||
rtable *src;
|
||||
rtable *dst;
|
||||
u32 uc;
|
||||
};
|
||||
#define RT_LOCK(tab) ({ LOCK_DOMAIN(rtable, (tab)->lock); &(tab)->priv; })
|
||||
#define RT_UNLOCK(tab) UNLOCK_DOMAIN(rtable, (tab)->lock)
|
||||
#define RT_PRIV(tab) ({ ASSERT_DIE(RT_IS_LOCKED((tab))); &(tab)->priv; })
|
||||
#define RT_PUB(tab) SKIP_BACK(rtable, priv, tab)
|
||||
|
||||
#define RT_LOCKED(tpub, tpriv) for (struct rtable_private *tpriv = RT_LOCK(tpub); tpriv; RT_UNLOCK(tpriv), (tpriv = NULL))
|
||||
#define RT_RETURN(tpriv, ...) do { RT_UNLOCK(tpriv); return __VA_ARGS__; } while (0)
|
||||
|
||||
#define RT_PRIV_SAME(tpriv, tpub) (&(tpub)->priv == (tpriv))
|
||||
|
||||
extern struct rt_cork {
|
||||
_Atomic uint active;
|
||||
@ -184,43 +205,12 @@ static inline int rt_cork_check(event *e)
|
||||
}
|
||||
|
||||
|
||||
#define NHU_CLEAN 0
|
||||
#define NHU_SCHEDULED 1
|
||||
#define NHU_RUNNING 2
|
||||
#define NHU_DIRTY 3
|
||||
|
||||
typedef struct network {
|
||||
struct rte_storage *routes; /* Available routes for this network */
|
||||
struct rt_pending_export *first, *last;
|
||||
struct fib_node n; /* FIB flags reserved for kernel syncer */
|
||||
} net;
|
||||
|
||||
struct hostcache {
|
||||
slab *slab; /* Slab holding all hostentries */
|
||||
struct hostentry **hash_table; /* Hash table for hostentries */
|
||||
unsigned hash_order, hash_shift;
|
||||
unsigned hash_max, hash_min;
|
||||
unsigned hash_items;
|
||||
linpool *lp; /* Linpool for trie */
|
||||
struct f_trie *trie; /* Trie of prefixes that might affect hostentries */
|
||||
list hostentries; /* List of all hostentries */
|
||||
byte update_hostcache;
|
||||
};
|
||||
|
||||
struct hostentry {
|
||||
node ln;
|
||||
ip_addr addr; /* IP address of host, part of key */
|
||||
ip_addr link; /* (link-local) IP address of host, used as gw
|
||||
if host is directly attached */
|
||||
struct rtable *tab; /* Dependent table, part of key */
|
||||
struct hostentry *next; /* Next in hash chain */
|
||||
unsigned hash_key; /* Hash key */
|
||||
unsigned uc; /* Use count */
|
||||
ea_list *src; /* Source attributes */
|
||||
byte nexthop_linkable; /* Nexthop list is completely non-device */
|
||||
u32 igp_metric; /* Chosen route IGP metric */
|
||||
};
|
||||
|
||||
struct rte_storage {
|
||||
struct rte_storage *next; /* Next in chain */
|
||||
struct rte rte; /* Route data */
|
||||
@ -238,6 +228,8 @@ struct rt_import_request {
|
||||
char *name;
|
||||
u8 trace_routes;
|
||||
|
||||
event_list *list; /* Where to schedule announce events */
|
||||
|
||||
void (*dump_req)(struct rt_import_request *req);
|
||||
void (*log_state_change)(struct rt_import_request *req, u8 state);
|
||||
/* Preimport is called when the @new route is just-to-be inserted, replacing @old.
|
||||
@ -269,6 +261,7 @@ struct rt_import_hook {
|
||||
u8 stale_pruning; /* Last prune started when this value was set at stale_valid */
|
||||
|
||||
void (*stopped)(struct rt_import_request *); /* Stored callback when import is stopped */
|
||||
event announce_event; /* This event announces table updates */
|
||||
};
|
||||
|
||||
struct rt_pending_export {
|
||||
@ -314,29 +307,44 @@ struct rt_export_hook {
|
||||
u32 withdraws_received; /* Number of route withdraws received */
|
||||
} stats;
|
||||
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
|
||||
_Atomic u8 export_state; /* Route export state (TES_*, see below) */
|
||||
struct event event; /* Event running all the export operations */
|
||||
|
||||
struct bmap seq_map; /* Keep track which exports were already procesed */
|
||||
|
||||
void (*stopped)(struct rt_export_request *); /* Stored callback when export is stopped */
|
||||
};
|
||||
|
||||
struct rt_table_export_hook {
|
||||
union {
|
||||
struct rt_export_hook h;
|
||||
struct { /* Overriding the parent structure beginning */
|
||||
node _n;
|
||||
struct rt_table_exporter *table;
|
||||
};
|
||||
};
|
||||
|
||||
union {
|
||||
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
|
||||
struct {
|
||||
struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */
|
||||
struct f_trie *walk_lock; /* Locked trie for walking */
|
||||
union { /* Last net visited but not processed */
|
||||
net_addr walk_last;
|
||||
net_addr_ip4 walk_last_ip4;
|
||||
net_addr_ip6 walk_last_ip6;
|
||||
};
|
||||
};
|
||||
u32 hash_iter; /* Iterator over hash */
|
||||
};
|
||||
|
||||
struct bmap seq_map; /* Keep track which exports were already procesed */
|
||||
|
||||
struct rt_pending_export * _Atomic last_export;/* Last export processed */
|
||||
struct rt_pending_export *_Atomic last_export;/* Last export processed */
|
||||
struct rt_pending_export *rpe_next; /* Next pending export to process */
|
||||
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
|
||||
u8 refeed_pending; /* Refeeding and another refeed is scheduled */
|
||||
_Atomic u8 export_state; /* Route export state (TES_*, see below) */
|
||||
u8 feed_type; /* Which feeding method is used (TFT_*, see below) */
|
||||
|
||||
struct event *event; /* Event running all the export operations */
|
||||
|
||||
void (*stopped)(struct rt_export_request *); /* Stored callback when export is stopped */
|
||||
};
|
||||
|
||||
#define TIS_DOWN 0
|
||||
@ -365,7 +373,8 @@ struct rt_export_hook {
|
||||
#define TFT_HASH 3
|
||||
|
||||
void rt_request_import(rtable *tab, struct rt_import_request *req);
|
||||
void rt_request_export(struct rt_exporter *tab, struct rt_export_request *req);
|
||||
void rt_request_export(rtable *tab, struct rt_export_request *req);
|
||||
void rt_request_export_other(struct rt_exporter *tab, struct rt_export_request *req);
|
||||
|
||||
void rt_export_once(struct rt_exporter *tab, struct rt_export_request *req);
|
||||
|
||||
@ -382,15 +391,35 @@ void rt_set_export_state(struct rt_export_hook *hook, u8 state);
|
||||
|
||||
void rte_import(struct rt_import_request *req, const net_addr *net, rte *new, struct rte_src *src);
|
||||
|
||||
/*
|
||||
* For table export processing
|
||||
*/
|
||||
|
||||
/* Get next rpe. If src is given, it must match. */
|
||||
struct rt_pending_export *rpe_next(struct rt_pending_export *rpe, struct rte_src *src);
|
||||
|
||||
/* Walk all rpe's */
|
||||
#define RPE_WALK(first, it, src) \
|
||||
for (struct rt_pending_export *it = (first); it; it = rpe_next(it, (src)))
|
||||
|
||||
/* Mark the pending export processed */
|
||||
void rpe_mark_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
|
||||
|
||||
#define rpe_mark_seen_all(hook, first, src) \
|
||||
RPE_WALK((first), _rpe, (src)) rpe_mark_seen((hook), _rpe)
|
||||
|
||||
/* Get pending export seen status */
|
||||
int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
|
||||
|
||||
/*
|
||||
* For rt_export_hook and rt_exporter inheritance
|
||||
*/
|
||||
|
||||
void rt_init_export(struct rt_exporter *re, struct rt_export_hook *hook);
|
||||
struct rt_export_hook *rt_alloc_export(struct rt_exporter *re, uint size);
|
||||
void rt_export_stopped(struct rt_export_hook *hook);
|
||||
void rt_exporter_init(struct rt_exporter *re);
|
||||
|
||||
/* Types of route announcement, also used as flags */
|
||||
#define RA_UNDEF 0 /* Undefined RA type */
|
||||
#define RA_OPTIMAL 1 /* Announcement of optimal route change */
|
||||
@ -404,6 +433,49 @@ int rpe_get_seen(struct rt_export_hook *hook, struct rt_pending_export *rpe);
|
||||
#define RIC_REJECT -1 /* Rejected by protocol */
|
||||
#define RIC_DROP -2 /* Silently dropped by protocol */
|
||||
|
||||
/*
|
||||
* Next hop update data structures
|
||||
*/
|
||||
|
||||
#define NHU_CLEAN 0
|
||||
#define NHU_SCHEDULED 1
|
||||
#define NHU_RUNNING 2
|
||||
#define NHU_DIRTY 3
|
||||
|
||||
struct hostentry {
|
||||
node ln;
|
||||
ip_addr addr; /* IP address of host, part of key */
|
||||
ip_addr link; /* (link-local) IP address of host, used as gw
|
||||
if host is directly attached */
|
||||
rtable *tab; /* Dependent table, part of key */
|
||||
struct hostentry *next; /* Next in hash chain */
|
||||
unsigned hash_key; /* Hash key */
|
||||
unsigned uc; /* Use count */
|
||||
ea_list *src; /* Source attributes */
|
||||
byte nexthop_linkable; /* Nexthop list is completely non-device */
|
||||
u32 igp_metric; /* Chosen route IGP metric */
|
||||
};
|
||||
|
||||
struct hostcache {
|
||||
slab *slab; /* Slab holding all hostentries */
|
||||
struct hostentry **hash_table; /* Hash table for hostentries */
|
||||
unsigned hash_order, hash_shift;
|
||||
unsigned hash_max, hash_min;
|
||||
unsigned hash_items;
|
||||
linpool *lp; /* Linpool for trie */
|
||||
struct f_trie *trie; /* Trie of prefixes that might affect hostentries */
|
||||
list hostentries; /* List of all hostentries */
|
||||
event update;
|
||||
struct rt_export_request req; /* Notifier */
|
||||
};
|
||||
|
||||
struct rt_flowspec_link {
|
||||
rtable *src;
|
||||
rtable *dst;
|
||||
u32 uc;
|
||||
struct rt_export_request req;
|
||||
};
|
||||
|
||||
#define rte_update channel_rte_import
|
||||
/**
|
||||
* rte_update - enter a new update to a routing table
|
||||
@ -446,32 +518,36 @@ void rt_init(void);
|
||||
void rt_preconfig(struct config *);
|
||||
void rt_postconfig(struct config *);
|
||||
void rt_commit(struct config *new, struct config *old);
|
||||
void rt_lock_table(rtable *);
|
||||
void rt_unlock_table(rtable *);
|
||||
struct f_trie * rt_lock_trie(rtable *tab);
|
||||
void rt_unlock_trie(rtable *tab, struct f_trie *trie);
|
||||
void rt_subscribe(rtable *tab, struct rt_subscription *s);
|
||||
void rt_unsubscribe(struct rt_subscription *s);
|
||||
void rt_lock_table_priv(struct rtable_private *, const char *file, uint line);
|
||||
void rt_unlock_table_priv(struct rtable_private *, const char *file, uint line);
|
||||
static inline void rt_lock_table_pub(rtable *t, const char *file, uint line)
|
||||
{ RT_LOCKED(t, tt) rt_lock_table_priv(tt, file, line); }
|
||||
static inline void rt_unlock_table_pub(rtable *t, const char *file, uint line)
|
||||
{ RT_LOCKED(t, tt) rt_unlock_table_priv(tt, file, line); }
|
||||
|
||||
#define rt_lock_table(t) _Generic((t), rtable *: rt_lock_table_pub, \
|
||||
struct rtable_private *: rt_lock_table_priv)((t), __FILE__, __LINE__)
|
||||
#define rt_unlock_table(t) _Generic((t), rtable *: rt_unlock_table_pub, \
|
||||
struct rtable_private *: rt_unlock_table_priv)((t), __FILE__, __LINE__)
|
||||
|
||||
struct f_trie * rt_lock_trie(struct rtable_private *tab);
|
||||
void rt_unlock_trie(struct rtable_private *tab, struct f_trie *trie);
|
||||
void rt_flowspec_link(rtable *src, rtable *dst);
|
||||
void rt_flowspec_unlink(rtable *src, rtable *dst);
|
||||
rtable *rt_setup(pool *, struct rtable_config *);
|
||||
static inline void rt_shutdown(rtable *r) { rfree(r->rp); }
|
||||
|
||||
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
|
||||
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
|
||||
static inline net *net_find(struct rtable_private *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
|
||||
static inline net *net_find_valid(struct rtable_private *tab, const net_addr *addr)
|
||||
{ net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; }
|
||||
static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
|
||||
net *net_get(rtable *tab, const net_addr *addr);
|
||||
net *net_route(rtable *tab, const net_addr *n);
|
||||
static inline net *net_get(struct rtable_private *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
|
||||
net *net_route(struct rtable_private *tab, const net_addr *n);
|
||||
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
|
||||
rte *rt_export_merged(struct channel *c, rte ** feed, uint count, linpool *pool, int silent);
|
||||
void rt_refresh_begin(struct rt_import_request *);
|
||||
void rt_refresh_end(struct rt_import_request *);
|
||||
void rt_modify_stale(rtable *t, struct rt_import_request *);
|
||||
void rt_schedule_prune(rtable *t);
|
||||
void rt_schedule_prune(struct rtable_private *t);
|
||||
void rte_dump(struct rte_storage *);
|
||||
void rte_free(struct rte_storage *);
|
||||
struct rte_storage *rte_store(const rte *, net *net, rtable *);
|
||||
void rt_dump(rtable *);
|
||||
void rt_dump_all(void);
|
||||
void rt_dump_hooks(rtable *);
|
||||
@ -481,6 +557,8 @@ void rt_reload_channel_abort(struct channel *c);
|
||||
void rt_refeed_channel(struct channel *c);
|
||||
void rt_prune_sync(rtable *t, int all);
|
||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||
void rt_new_default_table(struct symbol *s);
|
||||
struct rtable_config *rt_get_default_table(struct config *cf, uint addr_type);
|
||||
|
||||
static inline int rt_is_ip(rtable *tab)
|
||||
{ return (tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6); }
|
||||
@ -530,7 +608,7 @@ struct rt_show_data {
|
||||
|
||||
void rt_show(struct rt_show_data *);
|
||||
struct rt_show_data_rtable * rt_show_add_exporter(struct rt_show_data *d, struct rt_exporter *t, const char *name);
|
||||
struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, struct rtable *t);
|
||||
struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t);
|
||||
|
||||
/* Value of table definition mode in struct rt_show_data */
|
||||
#define RSD_TDB_DEFAULT 0 /* no table specified */
|
||||
@ -557,7 +635,7 @@ struct hostentry_adata {
|
||||
};
|
||||
|
||||
void
|
||||
ea_set_hostentry(ea_list **to, struct rtable *dep, struct rtable *tab, ip_addr gw, ip_addr ll, u32 lnum, u32 labels[lnum]);
|
||||
ea_set_hostentry(ea_list **to, rtable *dep, rtable *tab, ip_addr gw, ip_addr ll, u32 lnum, u32 labels[lnum]);
|
||||
|
||||
void ea_show_hostentry(const struct adata *ad, byte *buf, uint size);
|
||||
void ea_show_nexthop_list(struct cli *c, struct nexthop_adata *nhad);
|
||||
|
@ -113,7 +113,6 @@
|
||||
#define HASH_IP_EQ(a1,n1,a2,n2) ipa_equal(a1, a2) && n1 == n2
|
||||
#define HASH_IP_FN(a,n) ipa_hash(a) ^ u32_hash(n)
|
||||
|
||||
DEFINE_DOMAIN(rtable);
|
||||
#define BFD_LOCK LOCK_DOMAIN(rtable, bfd_global.lock)
|
||||
#define BFD_UNLOCK UNLOCK_DOMAIN(rtable, bfd_global.lock)
|
||||
|
||||
|
@ -1867,25 +1867,30 @@ bgp_free_pending_tx(struct bgp_channel *c)
|
||||
* Prefix hash table exporter
|
||||
*/
|
||||
|
||||
struct bgp_out_export_hook {
|
||||
struct rt_export_hook h;
|
||||
u32 hash_iter; /* Iterator over hash */
|
||||
};
|
||||
|
||||
static void
|
||||
bgp_out_table_feed(void *data)
|
||||
{
|
||||
struct rt_export_hook *hook = data;
|
||||
struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, hook->table);
|
||||
struct bgp_out_export_hook *hook = data;
|
||||
struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, hook->h.table);
|
||||
struct bgp_pending_tx *c = bc->ptx;
|
||||
|
||||
int max = 512;
|
||||
|
||||
const net_addr *neq = (hook->req->addr_mode == TE_ADDR_EQUAL) ? hook->req->addr : NULL;
|
||||
const net_addr *neq = (hook->h.req->addr_mode == TE_ADDR_EQUAL) ? hook->h.req->addr : NULL;
|
||||
const net_addr *cand = NULL;
|
||||
|
||||
do {
|
||||
HASH_WALK_ITER(c->prefix_hash, PXH, n, hook->hash_iter)
|
||||
{
|
||||
switch (hook->req->addr_mode)
|
||||
switch (hook->h.req->addr_mode)
|
||||
{
|
||||
case TE_ADDR_IN:
|
||||
if (!net_in_netX(n->net, hook->req->addr))
|
||||
if (!net_in_netX(n->net, hook->h.req->addr))
|
||||
continue;
|
||||
/* fall through */
|
||||
case TE_ADDR_NONE:
|
||||
@ -1897,7 +1902,7 @@ bgp_out_table_feed(void *data)
|
||||
case TE_ADDR_FOR:
|
||||
if (!neq)
|
||||
{
|
||||
if (net_in_netX(hook->req->addr, n->net) && (!cand || (n->net->length > cand->length)))
|
||||
if (net_in_netX(hook->h.req->addr, n->net) && (!cand || (n->net->length > cand->length)))
|
||||
cand = n->net;
|
||||
continue;
|
||||
}
|
||||
@ -1942,13 +1947,13 @@ bgp_out_table_feed(void *data)
|
||||
.new = &es, .new_best = &es,
|
||||
};
|
||||
|
||||
if (hook->req->export_bulk)
|
||||
if (hook->h.req->export_bulk)
|
||||
{
|
||||
rte *feed = &es.rte;
|
||||
hook->req->export_bulk(hook->req, n->net, &rpe, &feed, 1);
|
||||
hook->h.req->export_bulk(hook->h.req, n->net, &rpe, &feed, 1);
|
||||
}
|
||||
else if (hook->req->export_one)
|
||||
hook->req->export_one(hook->req, n->net, &rpe);
|
||||
else if (hook->h.req->export_one)
|
||||
hook->h.req->export_one(hook->h.req, n->net, &rpe);
|
||||
else
|
||||
bug("No export method in export request");
|
||||
}
|
||||
@ -1959,36 +1964,51 @@ bgp_out_table_feed(void *data)
|
||||
} while (neq);
|
||||
|
||||
if (hook->hash_iter)
|
||||
ev_schedule_work(hook->event);
|
||||
ev_schedule_work(&hook->h.event);
|
||||
else
|
||||
rt_set_export_state(hook, TES_READY);
|
||||
rt_set_export_state(&hook->h, TES_READY);
|
||||
}
|
||||
|
||||
static struct rt_export_hook *
|
||||
bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req UNUSED)
|
||||
static void
|
||||
bgp_out_table_export_start(struct rt_exporter *re, struct rt_export_request *req)
|
||||
{
|
||||
struct bgp_channel *bc = SKIP_BACK(struct bgp_channel, prefix_exporter, re);
|
||||
pool *p = rp_new(bc->c.proto->pool, "Export hook");
|
||||
struct rt_export_hook *hook = mb_allocz(p, sizeof(struct rt_export_hook));
|
||||
hook->pool = p;
|
||||
hook->event = ev_new_init(p, bgp_out_table_feed, hook);
|
||||
hook->feed_type = TFT_HASH;
|
||||
req->hook = rt_alloc_export(re, sizeof(struct bgp_out_export_hook));
|
||||
req->hook->req = req;
|
||||
|
||||
return hook;
|
||||
struct bgp_out_export_hook *hook = SKIP_BACK(struct bgp_out_export_hook, h, req->hook);
|
||||
|
||||
hook->h.event.hook = bgp_out_table_feed;
|
||||
rt_init_export(re, req->hook);
|
||||
}
|
||||
|
||||
static void
|
||||
bgp_out_table_export_done(void *data)
|
||||
{
|
||||
struct bgp_out_export_hook *hook = data;
|
||||
struct rt_export_request *req = hook->h.req;
|
||||
void (*stopped)(struct rt_export_request *) = hook->h.stopped;
|
||||
|
||||
rt_export_stopped(&hook->h);
|
||||
CALL(stopped, req);
|
||||
}
|
||||
|
||||
static const struct rt_exporter_class bgp_out_table_export_class = {
|
||||
.start = bgp_out_table_export_start,
|
||||
.done = bgp_out_table_export_done,
|
||||
};
|
||||
|
||||
void
|
||||
bgp_setup_out_table(struct bgp_channel *c)
|
||||
{
|
||||
ASSERT_DIE(c->c.out_table == NULL);
|
||||
|
||||
c->prefix_exporter = (struct rt_exporter) {
|
||||
.class = &bgp_out_table_export_class,
|
||||
.addr_type = c->c.table->addr_type,
|
||||
.start = bgp_out_table_export_start,
|
||||
.rp = c->c.proto->pool,
|
||||
};
|
||||
|
||||
init_list(&c->prefix_exporter.hooks);
|
||||
init_list(&c->prefix_exporter.pending);
|
||||
rt_exporter_init(&c->prefix_exporter);
|
||||
|
||||
c->c.out_table = &c->prefix_exporter;
|
||||
}
|
||||
@ -2510,7 +2530,7 @@ use_deterministic_med(struct rte_storage *r)
|
||||
}
|
||||
|
||||
int
|
||||
bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
|
||||
bgp_rte_recalculate(struct rtable_private *table, net *net, rte *new, rte *old, rte *old_best)
|
||||
{
|
||||
rte *key = new ? new : old;
|
||||
u32 lpref = rt_get_preference(key);
|
||||
|
@ -847,7 +847,7 @@ bgp_graceful_restart_feed(struct bgp_channel *c)
|
||||
.export_one = bgp_graceful_restart_drop_export,
|
||||
};
|
||||
|
||||
rt_request_export(&c->c.table->exporter, &c->stale_feed);
|
||||
rt_request_export(c->c.table, &c->stale_feed);
|
||||
}
|
||||
|
||||
|
||||
@ -1934,7 +1934,7 @@ bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32
|
||||
return cc2->c.table;
|
||||
|
||||
/* Last, try default table of given type */
|
||||
if (tab = cf->c.global->def_tables[type])
|
||||
if (tab = rt_get_default_table(cf->c.global, type))
|
||||
return tab;
|
||||
|
||||
cf_error("Undefined IGP table");
|
||||
@ -1953,7 +1953,7 @@ bgp_default_base_table(struct bgp_config *cf, struct bgp_channel_config *cc)
|
||||
return cc2->c.table;
|
||||
|
||||
/* Last, try default table of given type */
|
||||
struct rtable_config *tab = cf->c.global->def_tables[type];
|
||||
struct rtable_config *tab = rt_get_default_table(cf->c.global, type);
|
||||
if (tab)
|
||||
return tab;
|
||||
|
||||
|
@ -599,7 +599,7 @@ void bgp_done_prefix(struct bgp_channel *c, struct bgp_prefix *px, struct bgp_bu
|
||||
|
||||
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);
|
||||
int bgp_rte_recalculate(struct rtable_private *table, net *net, rte *new, rte *old, rte *old_best);
|
||||
void bgp_rte_modify_stale(struct rt_export_request *req, const net_addr *n, struct rt_pending_export *rpe UNUSED, rte **feed, uint count);
|
||||
u32 bgp_rte_igp_metric(const rte *);
|
||||
void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);
|
||||
|
@ -228,7 +228,7 @@ mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
|
||||
NODE_VALID(tn);
|
||||
tn = tn->next)
|
||||
{
|
||||
tab = SKIP_BACK(struct rtable, n, tn);
|
||||
tab = SKIP_BACK(rtable, n, tn);
|
||||
if (patmatch(pattern, tab->name) &&
|
||||
((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
|
||||
return tab;
|
||||
@ -243,13 +243,15 @@ mrt_next_table(struct mrt_table_dump_state *s)
|
||||
rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
|
||||
|
||||
if (s->table)
|
||||
rt_unlock_table(s->table);
|
||||
RT_LOCKED(s->table, tab)
|
||||
rt_unlock_table(tab);
|
||||
|
||||
s->table = tab;
|
||||
s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
|
||||
|
||||
if (s->table)
|
||||
rt_lock_table(s->table);
|
||||
RT_LOCKED(s->table, tab)
|
||||
rt_lock_table(tab);
|
||||
|
||||
return s->table;
|
||||
}
|
||||
@ -573,14 +575,18 @@ mrt_table_dump_init(pool *pp)
|
||||
static void
|
||||
mrt_table_dump_free(struct mrt_table_dump_state *s)
|
||||
{
|
||||
if (s->table_open)
|
||||
FIB_ITERATE_UNLINK(&s->fit, &s->table->fib);
|
||||
|
||||
if (s->table)
|
||||
rt_unlock_table(s->table);
|
||||
RT_LOCKED(s->table, tab)
|
||||
{
|
||||
if (s->table_open)
|
||||
FIB_ITERATE_UNLINK(&s->fit, &tab->fib);
|
||||
|
||||
rt_unlock_table(tab);
|
||||
}
|
||||
|
||||
if (s->table_ptr)
|
||||
rt_unlock_table(s->table_ptr);
|
||||
RT_LOCKED(s->table_ptr, tab)
|
||||
rt_unlock_table(tab);
|
||||
|
||||
config_del_obstacle(s->config);
|
||||
|
||||
@ -606,16 +612,19 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
|
||||
|
||||
mrt_peer_table_dump(s);
|
||||
|
||||
FIB_ITERATE_INIT(&s->fit, &s->table->fib);
|
||||
RT_LOCKED(s->table, tab)
|
||||
{
|
||||
|
||||
FIB_ITERATE_INIT(&s->fit, &tab->fib);
|
||||
s->table_open = 1;
|
||||
|
||||
step:
|
||||
FIB_ITERATE_START(&s->table->fib, &s->fit, net, n)
|
||||
FIB_ITERATE_START(&tab->fib, &s->fit, net, n)
|
||||
{
|
||||
if (s->max < 0)
|
||||
{
|
||||
FIB_ITERATE_PUT(&s->fit);
|
||||
return 0;
|
||||
RT_RETURN(tab, 0);
|
||||
}
|
||||
|
||||
/* With Always ADD_PATH option, we jump directly to second phase */
|
||||
@ -630,6 +639,8 @@ mrt_table_dump_step(struct mrt_table_dump_state *s)
|
||||
FIB_ITERATE_END;
|
||||
s->table_open = 0;
|
||||
|
||||
}
|
||||
|
||||
mrt_close_file(s);
|
||||
mrt_peer_table_flush(s);
|
||||
}
|
||||
@ -661,7 +672,8 @@ mrt_timer(timer *t)
|
||||
s->always_add_path = cf->always_add_path;
|
||||
|
||||
if (s->table_ptr)
|
||||
rt_lock_table(s->table_ptr);
|
||||
RT_LOCKED(s->table_ptr, tab)
|
||||
rt_lock_table(tab);
|
||||
|
||||
p->table_dump = s;
|
||||
ev_schedule(p->event);
|
||||
@ -737,7 +749,8 @@ mrt_dump_cmd(struct mrt_dump_data *d)
|
||||
s->filename = d->filename;
|
||||
|
||||
if (s->table_ptr)
|
||||
rt_lock_table(s->table_ptr);
|
||||
RT_LOCKED(s->table_ptr, tab)
|
||||
rt_lock_table(tab);
|
||||
|
||||
this_cli->cont = mrt_dump_cont;
|
||||
this_cli->cleanup = mrt_dump_cleanup;
|
||||
|
@ -40,7 +40,7 @@ struct mrt_proto {
|
||||
|
||||
struct mrt_dump_data {
|
||||
const char *table_expr;
|
||||
struct rtable *table_ptr;
|
||||
rtable *table_ptr;
|
||||
const struct filter *filter;
|
||||
const char *filename;
|
||||
};
|
||||
@ -60,7 +60,7 @@ struct mrt_table_dump_state {
|
||||
|
||||
/* Configuration information */
|
||||
const char *table_expr; /* Wildcard for table name (or NULL) */
|
||||
struct rtable *table_ptr; /* Explicit table (or NULL) */
|
||||
rtable *table_ptr; /* Explicit table (or NULL) */
|
||||
const struct filter *filter; /* Optional filter */
|
||||
const char *filename; /* Filename pattern */
|
||||
int always_add_path; /* Always use *_ADDPATH message subtypes */
|
||||
@ -73,7 +73,7 @@ struct mrt_table_dump_state {
|
||||
|
||||
HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */
|
||||
|
||||
struct rtable *table; /* Processed table, NULL initially */
|
||||
rtable *table; /* Processed table, NULL initially */
|
||||
struct fib_iterator fit; /* Iterator in processed table */
|
||||
int table_open; /* Whether iterator is linked */
|
||||
|
||||
|
@ -202,7 +202,9 @@ perf_loop(void *data)
|
||||
p->exp++;
|
||||
}
|
||||
|
||||
rt_schedule_prune(P->main_channel->table);
|
||||
RT_LOCKED(P->main_channel->table, tab)
|
||||
rt_schedule_prune(tab);
|
||||
|
||||
ev_schedule(p->loop);
|
||||
}
|
||||
|
||||
|
@ -1121,24 +1121,18 @@ rip_rte_proto(struct rte *rte)
|
||||
SKIP_BACK(struct rip_proto, p.sources, rte->src->owner) : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
rip_rte_better(struct rte *new, struct rte *old)
|
||||
{
|
||||
ASSERT_DIE(new->src == old->src);
|
||||
struct rip_proto *p = rip_rte_proto(new);
|
||||
|
||||
u32 new_metric = ea_get_int(new->attrs, &ea_rip_metric, p->infinity);
|
||||
u32 old_metric = ea_get_int(old->attrs, &ea_rip_metric, p->infinity);
|
||||
|
||||
return new_metric < old_metric;
|
||||
}
|
||||
|
||||
static u32
|
||||
rip_rte_igp_metric(const rte *rt)
|
||||
{
|
||||
return ea_get_int(rt->attrs, &ea_rip_metric, IGP_METRIC_UNKNOWN);
|
||||
}
|
||||
|
||||
static int
|
||||
rip_rte_better(struct rte *new, struct rte *old)
|
||||
{
|
||||
return rip_rte_igp_metric(new) < rip_rte_igp_metric(old);
|
||||
}
|
||||
|
||||
static void
|
||||
rip_postconfig(struct proto_config *CF)
|
||||
{
|
||||
|
@ -436,11 +436,11 @@ static_postconfig(struct proto_config *CF)
|
||||
|
||||
if (!cf->igp_table_ip4)
|
||||
cf->igp_table_ip4 = (cc->table->addr_type == NET_IP4) ?
|
||||
cc->table : cf->c.global->def_tables[NET_IP4];
|
||||
cc->table : rt_get_default_table(cf->c.global, NET_IP4);
|
||||
|
||||
if (!cf->igp_table_ip6)
|
||||
cf->igp_table_ip6 = (cc->table->addr_type == NET_IP6) ?
|
||||
cc->table : cf->c.global->def_tables[NET_IP6];
|
||||
cc->table : rt_get_default_table(cf->c.global, NET_IP6);
|
||||
|
||||
WALK_LIST(r, cf->routes)
|
||||
if (r->net && (r->net->type != CF->net_type))
|
||||
|
@ -366,6 +366,13 @@ rte_feed_obtain(net *n, rte **feed, uint count)
|
||||
static struct rte *
|
||||
krt_export_net(struct krt_proto *p, net *net)
|
||||
{
|
||||
/* FIXME: Here we are calling filters in table-locked context when exporting
|
||||
* to kernel. Here BIRD can crash if the user requested ROA check in kernel
|
||||
* export filter. It doesn't make much sense to write the filters like this,
|
||||
* therefore we may keep this unfinished piece of work here for later as it
|
||||
* won't really affect anybody. */
|
||||
ASSERT_DIE(RT_IS_LOCKED(p->p.main_channel->table));
|
||||
|
||||
struct channel *c = p->p.main_channel;
|
||||
const struct filter *filter = c->out_filter;
|
||||
|
||||
@ -446,6 +453,9 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
||||
#endif
|
||||
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
|
||||
|
||||
RT_LOCKED(p->p.main_channel->table, tab)
|
||||
{
|
||||
|
||||
/* Deleting all routes if flush is requested */
|
||||
if (p->flush_routes)
|
||||
goto delete;
|
||||
@ -454,7 +464,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
||||
if (!p->ready)
|
||||
goto ignore;
|
||||
|
||||
net *net = net_find(p->p.main_channel->table, e->net);
|
||||
net *net = net_find(tab, e->net);
|
||||
if (!net || !krt_is_installed(p, net))
|
||||
goto delete;
|
||||
|
||||
@ -499,7 +509,9 @@ delete:
|
||||
krt_replace_rte(p, e->net, NULL, e);
|
||||
goto done;
|
||||
|
||||
done:
|
||||
done:;
|
||||
}
|
||||
|
||||
lp_flush(krt_filter_lp);
|
||||
}
|
||||
|
||||
@ -512,7 +524,8 @@ krt_init_scan(struct krt_proto *p)
|
||||
static void
|
||||
krt_prune(struct krt_proto *p)
|
||||
{
|
||||
struct rtable *t = p->p.main_channel->table;
|
||||
RT_LOCKED(p->p.main_channel->table, t)
|
||||
{
|
||||
|
||||
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
|
||||
FIB_WALK(&t->fib, net, n)
|
||||
@ -534,6 +547,8 @@ krt_prune(struct krt_proto *p)
|
||||
|
||||
if (p->ready)
|
||||
p->initialized = 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user