mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 20:58:44 +00:00
Merge commit 'f81702b7' into haugesund
This commit is contained in:
commit
41572e0c1b
@ -425,6 +425,23 @@ filter_commit(struct config *new, struct config *old)
|
||||
}
|
||||
}
|
||||
|
||||
void channel_filter_dump(const struct filter *f)
|
||||
{
|
||||
if (f == FILTER_ACCEPT)
|
||||
debug(" ALL");
|
||||
else if (f == FILTER_REJECT)
|
||||
debug(" NONE");
|
||||
else if (f == FILTER_UNDEF)
|
||||
debug(" UNDEF");
|
||||
else if (f->sym) {
|
||||
ASSERT(f->sym->filter == f);
|
||||
debug(" named filter %s", f->sym->name);
|
||||
} else {
|
||||
debug("\n");
|
||||
f_dump_line(f->root, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void filters_dump_all(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
@ -444,19 +461,10 @@ void filters_dump_all(void)
|
||||
struct channel *c;
|
||||
WALK_LIST(c, sym->proto->proto->channels) {
|
||||
debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
|
||||
if (c->in_filter == FILTER_ACCEPT)
|
||||
debug(" ALL\n");
|
||||
else if (c->in_filter == FILTER_REJECT)
|
||||
debug(" NONE\n");
|
||||
else if (c->in_filter == FILTER_UNDEF)
|
||||
debug(" UNDEF\n");
|
||||
else if (c->in_filter->sym) {
|
||||
ASSERT(c->in_filter->sym->filter == c->in_filter);
|
||||
debug(" named filter %s\n", c->in_filter->sym->name);
|
||||
} else {
|
||||
debug("\n");
|
||||
f_dump_line(c->in_filter->root, 2);
|
||||
}
|
||||
channel_filter_dump(c->in_filter);
|
||||
debug(" EXPORT", c->name, net_label[c->net_type]);
|
||||
channel_filter_dump(c->out_filter);
|
||||
debug("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -851,8 +851,10 @@ CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]])
|
||||
{ neigh_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]])
|
||||
{ rta_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP ROUTES,,, [[Dump routing table]])
|
||||
CF_CLI(DUMP ROUTES,,, [[Dump routes]])
|
||||
{ rt_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP TABLES,,, [[Dump table connections]])
|
||||
{ rt_dump_hooks_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
|
||||
{ protos_dump_all(); cli_msg(0, ""); } ;
|
||||
CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])
|
||||
|
49
nest/limit.h
Normal file
49
nest/limit.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* BIRD Internet Routing Daemon -- Limits
|
||||
*
|
||||
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||
* (c) 2021 Maria Matejka <mq@jmq.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_LIMIT_H_
|
||||
#define _BIRD_LIMIT_H_
|
||||
|
||||
struct limit {
|
||||
u32 max;
|
||||
u32 count;
|
||||
int (*action)(struct limit *, void *data);
|
||||
};
|
||||
|
||||
static inline int limit_do_action(struct limit *l, void *data)
|
||||
{
|
||||
return l->action ? l->action(l, data) : 1;
|
||||
}
|
||||
|
||||
static inline int limit_push(struct limit *l, void *data)
|
||||
{
|
||||
if ((l->count >= l->max) && limit_do_action(l, data))
|
||||
return 1;
|
||||
|
||||
l->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void limit_pop(struct limit *l)
|
||||
{
|
||||
--l->count;
|
||||
}
|
||||
|
||||
static inline void limit_reset(struct limit *l)
|
||||
{
|
||||
l->count = 0;
|
||||
}
|
||||
|
||||
static inline void limit_update(struct limit *l, void *data, u32 max)
|
||||
{
|
||||
if (l->count > (l->max = max))
|
||||
limit_do_action(l, data);
|
||||
}
|
||||
|
||||
#endif
|
724
nest/proto.c
724
nest/proto.c
File diff suppressed because it is too large
Load Diff
123
nest/protocol.h
123
nest/protocol.h
@ -13,6 +13,7 @@
|
||||
#include "lib/resource.h"
|
||||
#include "lib/event.h"
|
||||
#include "nest/route.h"
|
||||
#include "nest/limit.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
struct iface;
|
||||
@ -76,7 +77,6 @@ struct protocol {
|
||||
void (*dump)(struct proto *); /* Debugging dump */
|
||||
int (*start)(struct proto *); /* Start the instance */
|
||||
int (*shutdown)(struct proto *); /* Stop the instance */
|
||||
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
|
||||
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
|
||||
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
|
||||
int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
|
||||
@ -132,33 +132,6 @@ struct proto_config {
|
||||
};
|
||||
|
||||
/* Protocol statistics */
|
||||
struct import_stats {
|
||||
/* Import - from protocol to core */
|
||||
u32 routes; /* Number of routes successfully imported to the (adjacent) routing table */
|
||||
u32 filtered; /* Number of routes rejected in import filter but kept in the routing table */
|
||||
u32 pref; /* Number of routes selected as best in the (adjacent) routing table */
|
||||
u32 updates_received; /* Number of route updates received */
|
||||
u32 updates_invalid; /* Number of route updates rejected as invalid */
|
||||
u32 updates_filtered; /* Number of route updates rejected by filters */
|
||||
u32 updates_ignored; /* Number of route updates rejected as already in route table */
|
||||
u32 updates_accepted; /* Number of route updates accepted and imported */
|
||||
u32 withdraws_received; /* Number of route withdraws received */
|
||||
u32 withdraws_invalid; /* Number of route withdraws rejected as invalid */
|
||||
u32 withdraws_ignored; /* Number of route withdraws rejected as already not in route table */
|
||||
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
|
||||
};
|
||||
|
||||
struct export_stats {
|
||||
/* Export - from core to protocol */
|
||||
u32 routes; /* Number of routes successfully exported to the protocol */
|
||||
u32 updates_received; /* Number of route updates received */
|
||||
u32 updates_rejected; /* Number of route updates rejected by protocol */
|
||||
u32 updates_filtered; /* Number of route updates rejected by filters */
|
||||
u32 updates_accepted; /* Number of route updates accepted and exported */
|
||||
u32 withdraws_received; /* Number of route withdraws received */
|
||||
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
|
||||
};
|
||||
|
||||
struct proto {
|
||||
node n; /* Node in global proto_list */
|
||||
struct protocol *proto; /* Protocol */
|
||||
@ -277,7 +250,7 @@ void channel_graceful_restart_unlock(struct channel *c);
|
||||
|
||||
#define DEFAULT_GR_WAIT 240
|
||||
|
||||
void channel_show_limit(struct channel_limit *l, const char *dsc);
|
||||
void channel_show_limit(struct limit *l, const char *dsc, int active, int action);
|
||||
void channel_show_info(struct channel *c);
|
||||
void channel_cmd_debug(struct channel *c, uint mask);
|
||||
|
||||
@ -432,18 +405,29 @@ extern struct proto_config *cf_dev_proto;
|
||||
#define PLA_RESTART 4 /* Force protocol restart */
|
||||
#define PLA_DISABLE 5 /* Shutdown and disable protocol */
|
||||
|
||||
#define PLS_INITIAL 0 /* Initial limit state after protocol start */
|
||||
#define PLS_ACTIVE 1 /* Limit was hit */
|
||||
#define PLS_BLOCKED 2 /* Limit is active and blocking new routes */
|
||||
|
||||
struct channel_limit {
|
||||
u32 limit; /* Maximum number of prefixes */
|
||||
u8 action; /* Action to take (PLA_*) */
|
||||
u8 state; /* State of limit (PLS_*) */
|
||||
};
|
||||
|
||||
void channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count);
|
||||
struct channel_limit_data {
|
||||
struct channel *c;
|
||||
int dir;
|
||||
};
|
||||
|
||||
#define CLP__RX(_c) (&(_c)->rx_limit)
|
||||
#define CLP__IN(_c) (&(_c)->in_limit)
|
||||
#define CLP__OUT(_c) (&(_c)->out_limit)
|
||||
|
||||
|
||||
#if 0
|
||||
#define CHANNEL_LIMIT_LOG(_c, _dir, _op) log(L_TRACE "%s.%s: %s limit %s %u", (_c)->proto->name, (_c)->name, #_dir, _op, (CLP__##_dir(_c))->count)
|
||||
#else
|
||||
#define CHANNEL_LIMIT_LOG(_c, _dir, _op)
|
||||
#endif
|
||||
|
||||
#define CHANNEL_LIMIT_PUSH(_c, _dir) ({ CHANNEL_LIMIT_LOG(_c, _dir, "push from"); struct channel_limit_data cld = { .c = (_c), .dir = PLD_##_dir }; limit_push(CLP__##_dir(_c), &cld); })
|
||||
#define CHANNEL_LIMIT_POP(_c, _dir) ({ limit_pop(CLP__##_dir(_c)); CHANNEL_LIMIT_LOG(_c, _dir, "pop to"); })
|
||||
|
||||
/*
|
||||
* Channels
|
||||
@ -486,6 +470,7 @@ struct channel_config {
|
||||
struct proto_config *parent; /* Where channel is defined (proto or template) */
|
||||
struct rtable_config *table; /* Table we're attached to */
|
||||
const struct filter *in_filter, *out_filter; /* Attached filters */
|
||||
|
||||
struct channel_limit rx_limit; /* Limit for receiving routes from protocol
|
||||
(relevant when in_keep_filtered is active) */
|
||||
struct channel_limit in_limit; /* Limit for importing routes from protocol */
|
||||
@ -502,7 +487,6 @@ struct channel_config {
|
||||
|
||||
struct channel {
|
||||
node n; /* Node in proto->channels */
|
||||
node table_node; /* Node in table->channels */
|
||||
|
||||
const char *name; /* Channel name (may be NULL) */
|
||||
const struct channel_class *channel;
|
||||
@ -513,14 +497,36 @@ struct channel {
|
||||
const struct filter *out_filter; /* Output filter */
|
||||
struct bmap export_map; /* Keeps track which routes were really exported */
|
||||
struct bmap export_reject_map; /* Keeps track which routes were rejected by export filter */
|
||||
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
|
||||
struct channel_limit in_limit; /* Input limit */
|
||||
struct channel_limit out_limit; /* Output limit */
|
||||
|
||||
struct event *feed_event; /* Event responsible for feeding */
|
||||
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
|
||||
struct import_stats import_stats; /* Import statistics */
|
||||
struct export_stats export_stats; /* Export statistics */
|
||||
struct limit rx_limit; /* Receive limit (for in_keep_filtered) */
|
||||
struct limit in_limit; /* Input limit */
|
||||
struct limit out_limit; /* Output limit */
|
||||
|
||||
u8 limit_actions[PLD_MAX]; /* Limit actions enum */
|
||||
u8 limit_active; /* Flags for active limits */
|
||||
|
||||
struct channel_import_stats {
|
||||
/* Import - from protocol to core */
|
||||
u32 updates_received; /* Number of route updates received */
|
||||
u32 updates_invalid; /* Number of route updates rejected as invalid */
|
||||
u32 updates_filtered; /* Number of route updates rejected by filters */
|
||||
u32 updates_limited_rx; /* Number of route updates exceeding the rx_limit */
|
||||
u32 updates_limited_in; /* Number of route updates exceeding the in_limit */
|
||||
u32 withdraws_received; /* Number of route withdraws received */
|
||||
u32 withdraws_invalid; /* Number of route withdraws rejected as invalid */
|
||||
} import_stats;
|
||||
|
||||
struct channel_export_stats {
|
||||
/* Export - from core to protocol */
|
||||
u32 updates_rejected; /* Number of route updates rejected by protocol */
|
||||
u32 updates_filtered; /* Number of route updates rejected by filters */
|
||||
u32 updates_accepted; /* Number of route updates accepted and exported */
|
||||
u32 updates_limited; /* Number of route updates exceeding the out_limit */
|
||||
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
|
||||
} export_stats;
|
||||
|
||||
struct rt_import_request in_req; /* Table import connection */
|
||||
struct rt_export_request out_req; /* Table export connection */
|
||||
|
||||
u32 refeed_count; /* Number of routes exported during refeed regardless of out_limit */
|
||||
|
||||
@ -534,10 +540,7 @@ struct channel {
|
||||
u8 stale; /* Used in reconfiguration */
|
||||
|
||||
u8 channel_state;
|
||||
u8 export_state; /* Route export state (ES_*, see below) */
|
||||
u8 feed_active;
|
||||
u8 flush_active;
|
||||
u8 refeeding; /* We are refeeding (valid only if export_state == ES_FEEDING) */
|
||||
u8 refeeding; /* Refeeding the channel. */
|
||||
u8 reloadable; /* Hook reload_routes() is allowed on the channel */
|
||||
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
|
||||
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
|
||||
@ -585,34 +588,34 @@ struct channel {
|
||||
* restricted by that and is on volition of the protocol. Generally, channels
|
||||
* are opened in protocols' start() hooks when going to PS_UP.
|
||||
*
|
||||
* CS_FLUSHING - The transitional state between initialized channel and closed
|
||||
* CS_STOP - The transitional state between initialized channel and closed
|
||||
* channel. The channel is still initialized, but no route exchange is allowed.
|
||||
* Instead, the associated table is running flush loop to remove routes imported
|
||||
* through the channel. After that, the channel changes state to CS_DOWN and
|
||||
* is detached from the table (the table is unlocked and the channel is unlinked
|
||||
* from it). Unlike other states, the CS_FLUSHING state is not explicitly
|
||||
* from it). Unlike other states, the CS_STOP state is not explicitly
|
||||
* entered or left by the protocol. A protocol may request to close a channel
|
||||
* (by calling channel_close()), which causes the channel to change state to
|
||||
* CS_FLUSHING and later to CS_DOWN. Also note that channels are closed
|
||||
* CS_STOP and later to CS_DOWN. Also note that channels are closed
|
||||
* automatically by the core when the protocol is going down.
|
||||
*
|
||||
* CS_PAUSE - Almost the same as CS_STOP, just the table import is kept and
|
||||
* the table export is stopped before transitioning to CS_START.
|
||||
*
|
||||
* Allowed transitions:
|
||||
*
|
||||
* CS_DOWN -> CS_START / CS_UP
|
||||
* CS_START -> CS_UP / CS_FLUSHING
|
||||
* CS_UP -> CS_START / CS_FLUSHING
|
||||
* CS_FLUSHING -> CS_DOWN (automatic)
|
||||
* CS_START -> CS_UP / CS_STOP
|
||||
* CS_UP -> CS_PAUSE / CS_STOP
|
||||
* CS_PAUSE -> CS_START (automatic)
|
||||
* CS_STOP -> CS_DOWN (automatic)
|
||||
*/
|
||||
|
||||
#define CS_DOWN 0
|
||||
#define CS_START 1
|
||||
#define CS_UP 2
|
||||
#define CS_FLUSHING 3
|
||||
|
||||
#define ES_DOWN 0
|
||||
#define ES_FEEDING 1
|
||||
#define ES_READY 2
|
||||
|
||||
#define CS_STOP 3
|
||||
#define CS_PAUSE 4
|
||||
|
||||
struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_type);
|
||||
static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
|
||||
@ -630,7 +633,7 @@ void channel_schedule_reload(struct channel *c);
|
||||
|
||||
static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
|
||||
static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
|
||||
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
|
||||
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_STOP); }
|
||||
|
||||
void channel_request_feeding(struct channel *c);
|
||||
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
|
||||
|
147
nest/route.h
147
nest/route.h
@ -2,6 +2,7 @@
|
||||
* BIRD Internet Routing Daemon -- Routing Table
|
||||
*
|
||||
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||
* (c) 2019--2021 Maria Matejka <mq@jmq.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -17,6 +18,7 @@
|
||||
struct ea_list;
|
||||
struct protocol;
|
||||
struct proto;
|
||||
struct channel;
|
||||
struct rte_src;
|
||||
struct symbol;
|
||||
struct timer;
|
||||
@ -165,12 +167,12 @@ typedef struct rtable {
|
||||
struct fib fib;
|
||||
struct f_trie *trie; /* Trie of prefixes defined in fib */
|
||||
char *name; /* Name of this table */
|
||||
list channels; /* List of attached channels (struct channel) */
|
||||
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 */
|
||||
|
||||
byte internal; /* Internal table of a protocol */
|
||||
list imports; /* Registered route importers */
|
||||
list exports; /* Registered route exporters */
|
||||
|
||||
struct hmap id_map;
|
||||
struct hostcache *hostcache;
|
||||
@ -188,6 +190,7 @@ typedef struct rtable {
|
||||
byte prune_trie; /* Prune prefix trie during next table prune */
|
||||
byte hcu_scheduled; /* Hostcache update is scheduled */
|
||||
byte nhu_state; /* Next Hop Update state */
|
||||
byte internal; /* This table is internal for some other object */
|
||||
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
|
||||
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
|
||||
struct f_trie *trie_new; /* New prefix trie defined during pruning */
|
||||
@ -257,7 +260,7 @@ typedef struct rte {
|
||||
struct rta *attrs; /* Attributes of this route */
|
||||
const net_addr *net; /* Network this RTE belongs to */
|
||||
struct rte_src *src; /* Route source that created the route */
|
||||
struct channel *sender; /* Channel used to send the route to the routing table */
|
||||
struct rt_import_hook *sender; /* Import hook used to send the route to the routing table */
|
||||
btime lastmod; /* Last modified (set by table) */
|
||||
u32 id; /* Table specific route id */
|
||||
byte flags; /* Table-specific flags */
|
||||
@ -281,15 +284,130 @@ struct rte_storage {
|
||||
#define REF_MODIFY 16 /* Route is scheduled for modify */
|
||||
|
||||
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
|
||||
static inline int rte_is_valid_rte(rte *r) { return r && !(r->flags & REF_FILTERED); }
|
||||
static inline int rte_is_valid_storage(struct rte_storage *r) { return r && rte_is_valid_rte(&r->rte); }
|
||||
static inline int rte_is_valid_rte(const rte *r) { return r && !(r->flags & REF_FILTERED); }
|
||||
static inline int rte_is_valid_storage(const struct rte_storage *r) { return r && rte_is_valid_rte(&r->rte); }
|
||||
|
||||
#define rte_is_valid(r) _Generic((*r), rte: rte_is_valid_rte, struct rte_storage: rte_is_valid_storage)(r)
|
||||
|
||||
/* Route just has REF_FILTERED flag */
|
||||
static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); }
|
||||
static inline int rte_is_filtered(const rte *r) { return !!(r->flags & REF_FILTERED); }
|
||||
|
||||
|
||||
/* Table-channel connections */
|
||||
|
||||
struct rt_import_request {
|
||||
struct rt_import_hook *hook; /* The table part of importer */
|
||||
char *name;
|
||||
u8 trace_routes;
|
||||
|
||||
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.
|
||||
* Return a route (may be different or modified in-place) to continue or NULL to withdraw. */
|
||||
struct rte *(*preimport)(struct rt_import_request *req, struct rte *new, struct rte *old);
|
||||
struct rte *(*rte_modify)(struct rte *, struct linpool *);
|
||||
};
|
||||
|
||||
struct rt_import_hook {
|
||||
node n;
|
||||
rtable *table; /* The connected table */
|
||||
struct rt_import_request *req; /* The requestor */
|
||||
|
||||
struct rt_import_stats {
|
||||
/* Import - from protocol to core */
|
||||
u32 pref; /* Number of routes selected as best in the (adjacent) routing table */
|
||||
u32 updates_ignored; /* Number of route updates rejected as already in route table */
|
||||
u32 updates_accepted; /* Number of route updates accepted and imported */
|
||||
u32 withdraws_ignored; /* Number of route withdraws rejected as already not in route table */
|
||||
u32 withdraws_accepted; /* Number of route withdraws accepted and processed */
|
||||
} stats;
|
||||
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
|
||||
u8 import_state; /* IS_* */
|
||||
|
||||
void (*stopped)(struct rt_import_request *); /* Stored callback when import is stopped */
|
||||
};
|
||||
|
||||
struct rt_pending_export {
|
||||
struct rte_storage *new, *new_best, *old, *old_best;
|
||||
};
|
||||
|
||||
struct rt_export_request {
|
||||
struct rt_export_hook *hook; /* Table part of the export */
|
||||
char *name;
|
||||
u8 trace_routes;
|
||||
|
||||
/* There are two methods of export. You can either request feeding every single change
|
||||
* or feeding the whole route feed. In case of regular export, &export_one is preferred.
|
||||
* Anyway, when feeding, &export_bulk is preferred, falling back to &export_one.
|
||||
* Thus, for RA_OPTIMAL, &export_one is only set,
|
||||
* for RA_MERGED and RA_ACCEPTED, &export_bulk is only set
|
||||
* and for RA_ANY, both are set to accomodate for feeding all routes but receiving single changes
|
||||
*/
|
||||
void (*export_one)(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe);
|
||||
void (*export_bulk)(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *rpe, rte **feed, uint count);
|
||||
|
||||
void (*dump_req)(struct rt_export_request *req);
|
||||
void (*log_state_change)(struct rt_export_request *req, u8);
|
||||
};
|
||||
|
||||
struct rt_export_hook {
|
||||
node n;
|
||||
rtable *table; /* The connected table */
|
||||
|
||||
pool *pool;
|
||||
linpool *lp;
|
||||
|
||||
struct rt_export_request *req; /* The requestor */
|
||||
|
||||
struct rt_export_stats {
|
||||
/* Export - from core to protocol */
|
||||
u32 updates_received; /* Number of route updates received */
|
||||
u32 withdraws_received; /* Number of route withdraws received */
|
||||
} stats;
|
||||
|
||||
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
|
||||
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
|
||||
u8 refeed_pending; /* Refeeding and another refeed is scheduled */
|
||||
u8 export_state; /* Route export state (TES_*, 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
|
||||
#define TIS_UP 1
|
||||
#define TIS_STOP 2
|
||||
#define TIS_FLUSHING 3
|
||||
#define TIS_WAITING 4
|
||||
#define TIS_CLEARED 5
|
||||
#define TIS_MAX 6
|
||||
|
||||
#define TES_DOWN 0
|
||||
#define TES_HUNGRY 1
|
||||
#define TES_FEEDING 2
|
||||
#define TES_READY 3
|
||||
#define TES_STOP 4
|
||||
#define TES_MAX 5
|
||||
|
||||
void rt_request_import(rtable *tab, struct rt_import_request *req);
|
||||
void rt_request_export(rtable *tab, struct rt_export_request *req);
|
||||
|
||||
void rt_stop_import(struct rt_import_request *, void (*stopped)(struct rt_import_request *));
|
||||
void rt_stop_export(struct rt_export_request *, void (*stopped)(struct rt_export_request *));
|
||||
|
||||
const char *rt_import_state_name(u8 state);
|
||||
const char *rt_export_state_name(u8 state);
|
||||
|
||||
static inline u8 rt_import_get_state(struct rt_import_hook *ih) { return ih ? ih->import_state : TIS_DOWN; }
|
||||
static inline u8 rt_export_get_state(struct rt_export_hook *eh) { return eh ? eh->export_state : TES_DOWN; }
|
||||
|
||||
void rte_import(struct rt_import_request *req, const net_addr *net, rte *new, struct rte_src *src);
|
||||
|
||||
/* Types of route announcement, also used as flags */
|
||||
#define RA_UNDEF 0 /* Undefined RA type */
|
||||
#define RA_OPTIMAL 1 /* Announcement of optimal route change */
|
||||
@ -303,6 +421,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
|
||||
#define RIC_REJECT -1 /* Rejected by protocol */
|
||||
#define RIC_DROP -2 /* Silently dropped by protocol */
|
||||
|
||||
#define rte_update channel_rte_import
|
||||
/**
|
||||
* rte_update - enter a new update to a routing table
|
||||
* @c: channel doing the update
|
||||
@ -362,23 +481,24 @@ net *net_get(rtable *tab, const net_addr *addr);
|
||||
net *net_route(rtable *tab, const net_addr *n);
|
||||
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
|
||||
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
|
||||
rte *rt_export_merged_show(struct channel *c, net *n, linpool *pool);
|
||||
void rt_refresh_begin(rtable *t, struct channel *c);
|
||||
void rt_refresh_end(rtable *t, struct channel *c);
|
||||
void rt_modify_stale(rtable *t, struct channel *c);
|
||||
rte *rt_export_merged(struct channel *c, rte ** feed, uint count, linpool *pool, int silent);
|
||||
void rt_refresh_begin(rtable *t, struct rt_import_request *);
|
||||
void rt_refresh_end(rtable *t, struct rt_import_request *);
|
||||
void rt_modify_stale(rtable *t, struct rt_import_request *);
|
||||
void rt_schedule_prune(rtable *t);
|
||||
void rte_dump(struct rte_storage *);
|
||||
void rte_free(struct rte_storage *, rtable *);
|
||||
struct rte_storage *rte_store(const rte *, net *net, rtable *);
|
||||
void rt_dump(rtable *);
|
||||
void rt_dump_all(void);
|
||||
int rt_feed_channel(struct channel *c);
|
||||
void rt_feed_channel_abort(struct channel *c);
|
||||
void rt_dump_hooks(rtable *);
|
||||
void rt_dump_hooks_all(void);
|
||||
int rt_reload_channel(struct channel *c);
|
||||
void rt_reload_channel_abort(struct channel *c);
|
||||
void rt_refeed_channel(struct channel *c);
|
||||
void rt_prune_sync(rtable *t, int all);
|
||||
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported);
|
||||
int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
|
||||
int rte_update_out(struct channel *c, const net_addr *n, rte *new, const rte *old, struct rte_storage **old_exported);
|
||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||
|
||||
static inline int rt_is_ip(rtable *tab)
|
||||
@ -418,6 +538,7 @@ struct rt_show_data {
|
||||
struct channel *export_channel;
|
||||
struct config *running_on_config;
|
||||
struct krt_proto *kernel;
|
||||
struct rt_export_hook *kernel_export_hook;
|
||||
int export_mode, addr_mode, primary_only, filtered, stats;
|
||||
|
||||
int table_open; /* Iteration (fit) is open */
|
||||
|
@ -99,6 +99,29 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
|
||||
rta_show(c, a);
|
||||
}
|
||||
|
||||
static uint
|
||||
rte_feed_count(net *n)
|
||||
{
|
||||
uint count = 0;
|
||||
for (struct rte_storage *e = n->routes; e; e = e->next)
|
||||
if (rte_is_valid(RTE_OR_NULL(e)))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
rte_feed_obtain(net *n, rte **feed, uint count)
|
||||
{
|
||||
uint i = 0;
|
||||
for (struct rte_storage *e = n->routes; e; e = e->next)
|
||||
if (rte_is_valid(RTE_OR_NULL(e)))
|
||||
{
|
||||
ASSERT_DIE(i < count);
|
||||
feed[i++] = &e->rte;
|
||||
}
|
||||
ASSERT_DIE(i == count);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
{
|
||||
@ -128,7 +151,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
struct rte e = er->rte;
|
||||
|
||||
/* Export channel is down, do not try to export routes to it */
|
||||
if (ec && (ec->export_state == ES_DOWN))
|
||||
if (ec && !ec->out_req.hook)
|
||||
goto skip;
|
||||
|
||||
if (d->export_mode == RSEM_EXPORTED)
|
||||
@ -143,7 +166,14 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
{
|
||||
/* Special case for merged export */
|
||||
pass = 1;
|
||||
rte *em = rt_export_merged_show(ec, n, c->show_pool);
|
||||
uint count = rte_feed_count(n);
|
||||
if (!count)
|
||||
goto skip;
|
||||
|
||||
rte **feed = alloca(count * sizeof(rte *));
|
||||
rte_feed_obtain(n, feed, count);
|
||||
rte *em = rt_export_merged(ec, feed, count, c->show_pool, 1);
|
||||
|
||||
if (em)
|
||||
e = *em;
|
||||
else
|
||||
@ -369,7 +399,7 @@ rt_show_get_default_tables(struct rt_show_data *d)
|
||||
{
|
||||
WALK_LIST(c, d->export_protocol->channels)
|
||||
{
|
||||
if (c->export_state == ES_DOWN)
|
||||
if (!c->out_req.hook)
|
||||
continue;
|
||||
|
||||
tab = rt_show_add_table(d, c->table);
|
||||
|
913
nest/rt-table.c
913
nest/rt-table.c
File diff suppressed because it is too large
Load Diff
@ -760,25 +760,25 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
|
||||
{
|
||||
case BGP_GRS_NONE:
|
||||
c->gr_active = BGP_GRS_ACTIVE;
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_refresh_begin(c->c.table, &c->c.in_req);
|
||||
break;
|
||||
|
||||
case BGP_GRS_ACTIVE:
|
||||
rt_refresh_end(c->c.table, &c->c);
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_refresh_end(c->c.table, &c->c.in_req);
|
||||
rt_refresh_begin(c->c.table, &c->c.in_req);
|
||||
break;
|
||||
|
||||
case BGP_GRS_LLGR:
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_modify_stale(c->c.table, &c->c);
|
||||
rt_refresh_begin(c->c.table, &c->c.in_req);
|
||||
rt_modify_stale(c->c.table, &c->c.in_req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just flush the routes */
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_refresh_end(c->c.table, &c->c);
|
||||
rt_refresh_begin(c->c.table, &c->c.in_req);
|
||||
rt_refresh_end(c->c.table, &c->c.in_req);
|
||||
}
|
||||
|
||||
/* Reset bucket and prefix tables */
|
||||
@ -819,7 +819,7 @@ bgp_graceful_restart_done(struct bgp_channel *c)
|
||||
BGP_TRACE(D_EVENTS, "Neighbor graceful restart done");
|
||||
|
||||
tm_stop(c->stale_timer);
|
||||
rt_refresh_end(c->c.table, &c->c);
|
||||
rt_refresh_end(c->c.table, &c->c.in_req);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -861,7 +861,7 @@ bgp_graceful_restart_timeout(timer *t)
|
||||
/* Channel is in GR, and supports LLGR -> start LLGR */
|
||||
c->gr_active = BGP_GRS_LLGR;
|
||||
tm_start(c->stale_timer, c->stale_time S);
|
||||
rt_modify_stale(c->c.table, &c->c);
|
||||
rt_modify_stale(c->c.table, &c->c.in_req);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -899,10 +899,10 @@ bgp_refresh_begin(struct bgp_channel *c)
|
||||
{ log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; }
|
||||
|
||||
c->load_state = BFS_REFRESHING;
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_refresh_begin(c->c.table, &c->c.in_req);
|
||||
|
||||
if (c->c.in_table)
|
||||
rt_refresh_begin(c->c.in_table, &c->c);
|
||||
rt_refresh_begin(c->c.in_table, &c->c.in_req);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -923,7 +923,7 @@ bgp_refresh_end(struct bgp_channel *c)
|
||||
{ log(L_WARN "%s: END-OF-RR received without prior BEGIN-OF-RR, ignoring", p->p.name); return; }
|
||||
|
||||
c->load_state = BFS_NONE;
|
||||
rt_refresh_end(c->c.table, &c->c);
|
||||
rt_refresh_end(c->c.table, &c->c.in_req);
|
||||
|
||||
if (c->c.in_table)
|
||||
rt_prune_sync(c->c.in_table, 0);
|
||||
|
@ -82,7 +82,7 @@ pipe_preexport(struct channel *c, rte *e)
|
||||
struct pipe_proto *p = (void *) c->proto;
|
||||
|
||||
/* Avoid direct loopbacks */
|
||||
if (e->sender == c)
|
||||
if (e->sender == c->in_req.hook)
|
||||
return -1;
|
||||
|
||||
/* Indirection check */
|
||||
@ -212,10 +212,18 @@ pipe_get_status(struct proto *P, byte *buf)
|
||||
static void
|
||||
pipe_show_stats(struct pipe_proto *p)
|
||||
{
|
||||
struct import_stats *s1i = &p->pri->import_stats;
|
||||
struct export_stats *s1e = &p->pri->export_stats;
|
||||
struct import_stats *s2i = &p->sec->import_stats;
|
||||
struct export_stats *s2e = &p->sec->export_stats;
|
||||
struct channel_import_stats *s1i = &p->pri->import_stats;
|
||||
struct channel_export_stats *s1e = &p->pri->export_stats;
|
||||
struct channel_import_stats *s2i = &p->sec->import_stats;
|
||||
struct channel_export_stats *s2e = &p->sec->export_stats;
|
||||
|
||||
struct rt_import_stats *rs1i = p->pri->in_req.hook ? &p->pri->in_req.hook->stats : NULL;
|
||||
struct rt_export_stats *rs1e = p->pri->out_req.hook ? &p->pri->out_req.hook->stats : NULL;
|
||||
struct rt_import_stats *rs2i = p->sec->in_req.hook ? &p->sec->in_req.hook->stats : NULL;
|
||||
struct rt_export_stats *rs2e = p->sec->out_req.hook ? &p->sec->out_req.hook->stats : NULL;
|
||||
|
||||
u32 pri_routes = p->pri->in_limit.count;
|
||||
u32 sec_routes = p->sec->in_limit.count;
|
||||
|
||||
/*
|
||||
* Pipe stats (as anything related to pipes) are a bit tricky. There
|
||||
@ -239,24 +247,22 @@ pipe_show_stats(struct pipe_proto *p)
|
||||
*/
|
||||
|
||||
cli_msg(-1006, " Routes: %u imported, %u exported",
|
||||
s1i->routes, s2i->routes);
|
||||
pri_routes, sec_routes);
|
||||
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
|
||||
cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
|
||||
s2e->updates_received, s2e->updates_rejected + s1i->updates_invalid,
|
||||
s2e->updates_filtered, s1i->updates_ignored, s1i->updates_accepted);
|
||||
rs2e->updates_received, s2e->updates_rejected + s1i->updates_invalid,
|
||||
s2e->updates_filtered, rs1i->updates_ignored, rs1i->updates_accepted);
|
||||
cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
|
||||
s2e->withdraws_received, s1i->withdraws_invalid,
|
||||
s1i->withdraws_ignored, s1i->withdraws_accepted);
|
||||
rs2e->withdraws_received, s1i->withdraws_invalid,
|
||||
rs1i->withdraws_ignored, rs1i->withdraws_accepted);
|
||||
cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
|
||||
s1e->updates_received, s1e->updates_rejected + s2i->updates_invalid,
|
||||
s1e->updates_filtered, s2i->updates_ignored, s2i->updates_accepted);
|
||||
rs1e->updates_received, s1e->updates_rejected + s2i->updates_invalid,
|
||||
s1e->updates_filtered, rs2i->updates_ignored, rs2i->updates_accepted);
|
||||
cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
|
||||
s1e->withdraws_received, s2i->withdraws_invalid,
|
||||
s2i->withdraws_ignored, s2i->withdraws_accepted);
|
||||
rs1e->withdraws_received, s2i->withdraws_invalid,
|
||||
rs2i->withdraws_ignored, rs2i->withdraws_accepted);
|
||||
}
|
||||
|
||||
static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" };
|
||||
|
||||
static void
|
||||
pipe_show_proto_info(struct proto *P)
|
||||
{
|
||||
@ -265,13 +271,17 @@ pipe_show_proto_info(struct proto *P)
|
||||
cli_msg(-1006, " Channel %s", "main");
|
||||
cli_msg(-1006, " Table: %s", p->pri->table->name);
|
||||
cli_msg(-1006, " Peer table: %s", p->sec->table->name);
|
||||
cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]);
|
||||
cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]);
|
||||
cli_msg(-1006, " Import state: %s", rt_export_state_name(rt_export_get_state(p->sec->out_req.hook)));
|
||||
cli_msg(-1006, " Export state: %s", rt_export_state_name(rt_export_get_state(p->pri->out_req.hook)));
|
||||
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
|
||||
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter));
|
||||
|
||||
channel_show_limit(&p->pri->in_limit, "Import limit:");
|
||||
channel_show_limit(&p->sec->in_limit, "Export limit:");
|
||||
|
||||
|
||||
channel_show_limit(&p->pri->in_limit, "Import limit:",
|
||||
(p->pri->limit_active & (1 << PLD_IN)), p->pri->limit_actions[PLD_IN]);
|
||||
channel_show_limit(&p->sec->in_limit, "Export limit:",
|
||||
(p->sec->limit_active & (1 << PLD_IN)), p->sec->limit_actions[PLD_IN]);
|
||||
|
||||
if (P->proto_state != PS_DOWN)
|
||||
pipe_show_stats(p);
|
||||
|
@ -661,9 +661,9 @@ rpki_handle_cache_response_pdu(struct rpki_cache *cache, const struct pdu_cache_
|
||||
* a refresh cycle.
|
||||
*/
|
||||
if (cache->p->roa4_channel)
|
||||
rt_refresh_begin(cache->p->roa4_channel->table, cache->p->roa4_channel);
|
||||
rt_refresh_begin(cache->p->roa4_channel->table, &cache->p->roa4_channel->in_req);
|
||||
if (cache->p->roa6_channel)
|
||||
rt_refresh_begin(cache->p->roa6_channel->table, cache->p->roa6_channel);
|
||||
rt_refresh_begin(cache->p->roa6_channel->table, &cache->p->roa6_channel->in_req);
|
||||
|
||||
cache->p->refresh_channels = 1;
|
||||
}
|
||||
@ -846,9 +846,9 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da
|
||||
{
|
||||
cache->p->refresh_channels = 0;
|
||||
if (cache->p->roa4_channel)
|
||||
rt_refresh_end(cache->p->roa4_channel->table, cache->p->roa4_channel);
|
||||
rt_refresh_end(cache->p->roa4_channel->table, &cache->p->roa4_channel->in_req);
|
||||
if (cache->p->roa6_channel)
|
||||
rt_refresh_end(cache->p->roa6_channel->table, cache->p->roa6_channel);
|
||||
rt_refresh_end(cache->p->roa6_channel->table, &cache->p->roa6_channel->in_req);
|
||||
}
|
||||
|
||||
cache->last_update = current_time();
|
||||
@ -924,6 +924,9 @@ rpki_rx_hook(struct birdsock *sk, uint size)
|
||||
struct rpki_cache *cache = sk->data;
|
||||
struct rpki_proto *p = cache->p;
|
||||
|
||||
if ((p->p.proto_state == PS_DOWN) || (p->cache != cache))
|
||||
return 0;
|
||||
|
||||
byte *pkt_start = sk->rbuf;
|
||||
byte *end = pkt_start + size;
|
||||
|
||||
@ -980,6 +983,8 @@ rpki_err_hook(struct birdsock *sk, int error_num)
|
||||
CACHE_TRACE(D_EVENTS, cache, "The other side closed a connection");
|
||||
}
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
rpki_cache_change_state(cache, RPKI_CS_ERROR_TRANSPORT);
|
||||
}
|
||||
@ -999,6 +1004,9 @@ rpki_tx_hook(sock *sk)
|
||||
{
|
||||
struct rpki_cache *cache = sk->data;
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
while (rpki_fire_tx(cache) > 0)
|
||||
;
|
||||
}
|
||||
@ -1008,6 +1016,9 @@ rpki_connected_hook(sock *sk)
|
||||
{
|
||||
struct rpki_cache *cache = sk->data;
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
CACHE_TRACE(D_EVENTS, cache, "Connected");
|
||||
proto_notify_state(&cache->p->p, PS_UP);
|
||||
|
||||
|
@ -384,6 +384,9 @@ rpki_refresh_hook(timer *tm)
|
||||
{
|
||||
struct rpki_cache *cache = tm->data;
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
CACHE_DBG(cache, "%s", rpki_cache_state_to_str(cache->state));
|
||||
|
||||
switch (cache->state)
|
||||
@ -430,6 +433,9 @@ rpki_retry_hook(timer *tm)
|
||||
{
|
||||
struct rpki_cache *cache = tm->data;
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
CACHE_DBG(cache, "%s", rpki_cache_state_to_str(cache->state));
|
||||
|
||||
switch (cache->state)
|
||||
@ -475,6 +481,9 @@ rpki_expire_hook(timer *tm)
|
||||
{
|
||||
struct rpki_cache *cache = tm->data;
|
||||
|
||||
if (cache->p->cache != cache)
|
||||
return;
|
||||
|
||||
if (!cache->last_update)
|
||||
return;
|
||||
|
||||
|
@ -507,19 +507,13 @@ static_shutdown(struct proto *P)
|
||||
WALK_LIST(r, cf->routes)
|
||||
static_reset_rte(p, r);
|
||||
|
||||
return PS_DOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
static_cleanup(struct proto *P)
|
||||
{
|
||||
struct static_proto *p = (void *) P;
|
||||
|
||||
if (p->igp_table_ip4)
|
||||
rt_unlock_table(p->igp_table_ip4);
|
||||
|
||||
if (p->igp_table_ip6)
|
||||
rt_unlock_table(p->igp_table_ip6);
|
||||
|
||||
return PS_DOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -777,7 +771,6 @@ struct protocol proto_static = {
|
||||
.dump = static_dump,
|
||||
.start = static_start,
|
||||
.shutdown = static_shutdown,
|
||||
.cleanup = static_cleanup,
|
||||
.reconfigure = static_reconfigure,
|
||||
.copy_config = static_copy_config,
|
||||
.get_route_info = static_get_route_info,
|
||||
|
@ -542,21 +542,27 @@ krt_is_installed(struct krt_proto *p, net *n)
|
||||
return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->rte.id);
|
||||
}
|
||||
|
||||
static void
|
||||
krt_flush_routes(struct krt_proto *p)
|
||||
static uint
|
||||
rte_feed_count(net *n)
|
||||
{
|
||||
struct rtable *t = p->p.main_channel->table;
|
||||
uint count = 0;
|
||||
for (struct rte_storage *e = n->routes; e; e = e->next)
|
||||
if (rte_is_valid(RTE_OR_NULL(e)))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
|
||||
FIB_WALK(&t->fib, net, n)
|
||||
static void
|
||||
rte_feed_obtain(net *n, rte **feed, uint count)
|
||||
{
|
||||
uint i = 0;
|
||||
for (struct rte_storage *e = n->routes; e; e = e->next)
|
||||
if (rte_is_valid(RTE_OR_NULL(e)))
|
||||
{
|
||||
if (krt_is_installed(p, n))
|
||||
{
|
||||
/* FIXME: this does not work if gw is changed in export filter */
|
||||
krt_replace_rte(p, n->n.addr, NULL, &n->routes->rte);
|
||||
}
|
||||
ASSERT_DIE(i < count);
|
||||
feed[i++] = &e->rte;
|
||||
}
|
||||
FIB_WALK_END;
|
||||
ASSERT_DIE(i == count);
|
||||
}
|
||||
|
||||
static struct rte *
|
||||
@ -566,7 +572,15 @@ krt_export_net(struct krt_proto *p, net *net)
|
||||
const struct filter *filter = c->out_filter;
|
||||
|
||||
if (c->ra_mode == RA_MERGED)
|
||||
return rt_export_merged_show(c, net, krt_filter_lp);
|
||||
{
|
||||
uint count = rte_feed_count(net);
|
||||
if (!count)
|
||||
return NULL;
|
||||
|
||||
rte **feed = alloca(count * sizeof(rte *));
|
||||
rte_feed_obtain(net, feed, count);
|
||||
return rt_export_merged(c, feed, count, krt_filter_lp, 1);
|
||||
}
|
||||
|
||||
static _Thread_local rte rt;
|
||||
rt = net->routes->rte;
|
||||
@ -637,6 +651,9 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
||||
#endif
|
||||
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
|
||||
|
||||
/* Deleting all routes if flush is requested */
|
||||
if (p->flush_routes)
|
||||
goto delete;
|
||||
|
||||
/* We wait for the initial feed to have correct installed state */
|
||||
if (!p->ready)
|
||||
@ -729,6 +746,17 @@ krt_prune(struct krt_proto *p)
|
||||
p->initialized = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
krt_flush_routes(struct krt_proto *p)
|
||||
{
|
||||
KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
|
||||
p->flush_routes = 1;
|
||||
krt_init_scan(p);
|
||||
krt_do_scan(p);
|
||||
/* No prune! */
|
||||
p->flush_routes = 0;
|
||||
}
|
||||
|
||||
void
|
||||
krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
|
||||
{
|
||||
|
@ -66,6 +66,7 @@ struct krt_proto {
|
||||
byte ready; /* Initial feed has been finished */
|
||||
byte initialized; /* First scan has been finished */
|
||||
byte reload; /* Next scan is doing reload */
|
||||
byte flush_routes; /* Scanning to flush */
|
||||
};
|
||||
|
||||
extern pool *krt_pool;
|
||||
|
Loading…
Reference in New Issue
Block a user