0
0
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:
Maria Matejka 2022-10-04 16:09:41 +02:00
commit f69ba3921a
21 changed files with 1482 additions and 908 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

File diff suppressed because it is too large Load Diff

264
nest/rt.h
View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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))

View File

@ -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