0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 07:31:54 +00:00

Limit containment

This commit is contained in:
Maria Matejka 2021-11-06 20:34:16 +01:00
parent 46739f007a
commit 3a8197a9dc
5 changed files with 269 additions and 202 deletions

49
nest/limit.h Normal file
View 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

View File

@ -52,9 +52,9 @@ static void channel_request_reload(struct channel *c);
static void proto_shutdown_loop(timer *); static void proto_shutdown_loop(timer *);
static void proto_rethink_goal(struct proto *p); static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p); static char *proto_state_name(struct proto *p);
static void channel_verify_limits(struct channel *c); static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
static inline void channel_reset_limit(struct channel_limit *l); static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
static inline int proto_is_done(struct proto *p) static inline int proto_is_done(struct proto *p)
{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); } { return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
@ -168,9 +168,10 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->in_filter = cf->in_filter; c->in_filter = cf->in_filter;
c->out_filter = cf->out_filter; c->out_filter = cf->out_filter;
c->rx_limit = cf->rx_limit;
c->in_limit = cf->in_limit; channel_init_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit);
c->out_limit = cf->out_limit; channel_init_limit(c, &c->in_limit, PLD_IN, &cf->in_limit);
channel_init_limit(c, &c->out_limit, PLD_OUT, &cf->out_limit);
c->net_type = cf->net_type; c->net_type = cf->net_type;
c->ra_mode = cf->ra_mode; c->ra_mode = cf->ra_mode;
@ -280,14 +281,12 @@ channel_feed_loop(void *ptr)
} }
/* Reset export limit if the feed ended with acceptable number of exported routes */ /* Reset export limit if the feed ended with acceptable number of exported routes */
struct channel_limit *l = &c->out_limit;
if (c->refeeding && if (c->refeeding &&
(l->state == PLS_BLOCKED) && (c->limit_active & (1 << PLD_OUT)) &&
(c->refeed_count <= l->limit) && (c->refeed_count <= c->out_limit.max))
(c->export_stats.routes <= l->limit))
{ {
log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, l->limit); log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, c->out_limit.max);
channel_reset_limit(&c->out_limit); channel_reset_limit(c, &c->out_limit, PLD_OUT);
/* Continue in feed - it will process routing table again from beginning */ /* Continue in feed - it will process routing table again from beginning */
c->refeed_count = 0; c->refeed_count = 0;
@ -461,7 +460,8 @@ channel_stop_export(struct channel *c)
rt_feed_channel_abort(c); rt_feed_channel_abort(c);
c->export_state = ES_DOWN; c->export_state = ES_DOWN;
c->export_stats.routes = 0;
channel_reset_limit(c, &c->out_limit, PLD_OUT);
bmap_reset(&c->export_map, 1024); bmap_reset(&c->export_map, 1024);
bmap_reset(&c->export_reject_map, 1024); bmap_reset(&c->export_reject_map, 1024);
} }
@ -556,9 +556,9 @@ channel_do_start(struct channel *c)
memset(&c->export_stats, 0, sizeof(struct export_stats)); memset(&c->export_stats, 0, sizeof(struct export_stats));
memset(&c->import_stats, 0, sizeof(struct import_stats)); memset(&c->import_stats, 0, sizeof(struct import_stats));
channel_reset_limit(&c->rx_limit); channel_reset_limit(c, &c->rx_limit, PLD_RX);
channel_reset_limit(&c->in_limit); channel_reset_limit(c, &c->in_limit, PLD_IN);
channel_reset_limit(&c->out_limit); channel_reset_limit(c, &c->out_limit, PLD_OUT);
CALL(c->channel->start, c); CALL(c->channel->start, c);
} }
@ -604,8 +604,8 @@ channel_do_down(struct channel *c)
rt_unlock_table(c->table); rt_unlock_table(c->table);
c->proto->active_channels--; c->proto->active_channels--;
if ((c->import_stats.routes + c->import_stats.filtered) != 0) if (c->in_limit.count || c->rx_limit.count)
log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name); bug("%s: Channel %s is down but still has some routes", c->proto->name, c->name);
// bmap_free(&c->export_map); // bmap_free(&c->export_map);
memset(&c->import_stats, 0, sizeof(struct import_stats)); memset(&c->import_stats, 0, sizeof(struct import_stats));
@ -748,8 +748,8 @@ channel_request_reload(struct channel *c)
* Should this be done before reload_routes() hook? * Should this be done before reload_routes() hook?
* Perhaps, but routes are updated asynchronously. * Perhaps, but routes are updated asynchronously.
*/ */
channel_reset_limit(&c->rx_limit); channel_reset_limit(c, &c->rx_limit, PLD_RX);
channel_reset_limit(&c->in_limit); channel_reset_limit(c, &c->in_limit, PLD_IN);
} }
const struct channel_class channel_basic = { const struct channel_class channel_basic = {
@ -852,9 +852,10 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
/* Reconfigure channel fields */ /* Reconfigure channel fields */
c->in_filter = cf->in_filter; c->in_filter = cf->in_filter;
c->out_filter = cf->out_filter; c->out_filter = cf->out_filter;
c->rx_limit = cf->rx_limit;
c->in_limit = cf->in_limit; channel_update_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit);
c->out_limit = cf->out_limit; channel_update_limit(c, &c->in_limit, PLD_IN, &cf->in_limit);
channel_update_limit(c, &c->out_limit, PLD_OUT, &cf->out_limit);
// c->ra_mode = cf->ra_mode; // c->ra_mode = cf->ra_mode;
c->merge_limit = cf->merge_limit; c->merge_limit = cf->merge_limit;
@ -863,8 +864,6 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
c->in_keep_filtered = cf->in_keep_filtered; c->in_keep_filtered = cf->in_keep_filtered;
c->rpki_reload = cf->rpki_reload; c->rpki_reload = cf->rpki_reload;
channel_verify_limits(c);
/* Execute channel-specific reconfigure hook */ /* Execute channel-specific reconfigure hook */
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed)) if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
return 0; return 0;
@ -1785,88 +1784,104 @@ proto_set_message(struct proto *p, char *msg, int len)
} }
static const char * static const char * channel_limit_name[] = {
channel_limit_name(struct channel_limit *l)
{
const char *actions[] = {
[PLA_WARN] = "warn", [PLA_WARN] = "warn",
[PLA_BLOCK] = "block", [PLA_BLOCK] = "block",
[PLA_RESTART] = "restart", [PLA_RESTART] = "restart",
[PLA_DISABLE] = "disable", [PLA_DISABLE] = "disable",
}; };
return actions[l->action];
}
/** static void
* channel_notify_limit: notify about limit hit and take appropriate action channel_log_limit(struct channel *c, struct limit *l, int dir)
* @c: channel
* @l: limit being hit
* @dir: limit direction (PLD_*)
* @rt_count: the number of routes
*
* The function is called by the route processing core when limit @l
* is breached. It activates the limit and tooks appropriate action
* according to @l->action.
*/
void
channel_notify_limit(struct channel *c, struct channel_limit *l, int dir, u32 rt_count)
{ {
const char *dir_name[PLD_MAX] = { "receive", "import" , "export" }; const char *dir_name[PLD_MAX] = { "receive", "import" , "export" };
const byte dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT }; log(L_WARN "Channel %s.%s hits route %s limit (%d), action: %s",
struct proto *p = c->proto; c->proto->name, c->name, dir_name[dir], l->max, channel_limit_name[c->limit_actions[dir]]);
if (l->state == PLS_BLOCKED)
return;
/* For warning action, we want the log message every time we hit the limit */
if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
p->name, dir_name[dir], l->limit, channel_limit_name(l));
switch (l->action)
{
case PLA_WARN:
l->state = PLS_ACTIVE;
break;
case PLA_BLOCK:
l->state = PLS_BLOCKED;
break;
case PLA_RESTART:
case PLA_DISABLE:
l->state = PLS_BLOCKED;
if (p->proto_state == PS_UP)
proto_schedule_down(p, l->action == PLA_RESTART, dir_down[dir]);
break;
}
} }
static void static void
channel_verify_limits(struct channel *c) channel_activate_limit(struct channel *c, struct limit *l, int dir)
{ {
struct channel_limit *l; if (c->limit_active & (1 << dir))
u32 all_routes = c->import_stats.routes + c->import_stats.filtered; return;
l = &c->rx_limit; c->limit_active |= (1 << dir);
if (l->action && (all_routes > l->limit)) channel_log_limit(c, l, dir);
channel_notify_limit(c, l, PLD_RX, all_routes);
l = &c->in_limit;
if (l->action && (c->import_stats.routes > l->limit))
channel_notify_limit(c, l, PLD_IN, c->import_stats.routes);
l = &c->out_limit;
if (l->action && (c->export_stats.routes > l->limit))
channel_notify_limit(c, l, PLD_OUT, c->export_stats.routes);
} }
static inline void static int
channel_reset_limit(struct channel_limit *l) channel_limit_warn(struct limit *l, void *data)
{ {
if (l->action) struct channel_limit_data *cld = data;
l->state = PLS_INITIAL; struct channel *c = cld->c;
int dir = cld->dir;
channel_log_limit(c, l, dir);
return 0;
}
static int
channel_limit_block(struct limit *l, void *data)
{
struct channel_limit_data *cld = data;
struct channel *c = cld->c;
int dir = cld->dir;
channel_activate_limit(c, l, dir);
return 1;
}
static const byte chl_dir_down[PLD_MAX] = { PDC_RX_LIMIT_HIT, PDC_IN_LIMIT_HIT, PDC_OUT_LIMIT_HIT };
static int
channel_limit_down(struct limit *l, void *data)
{
struct channel_limit_data *cld = data;
struct channel *c = cld->c;
struct proto *p = c->proto;
int dir = cld->dir;
channel_activate_limit(c, l, dir);
if (p->proto_state == PS_UP)
proto_schedule_down(p, c->limit_actions[dir] == PLA_RESTART, chl_dir_down[dir]);
return 1;
}
static int (*channel_limit_action[])(struct limit *, void *) = {
[PLA_NONE] = NULL,
[PLA_WARN] = channel_limit_warn,
[PLA_BLOCK] = channel_limit_block,
[PLA_RESTART] = channel_limit_down,
[PLA_DISABLE] = channel_limit_down,
};
static void
channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf)
{
l->action = channel_limit_action[cf->action];
c->limit_actions[dir] = cf->action;
struct channel_limit_data cld = { .c = c, .dir = dir };
limit_update(l, &cld, cf->action ? cf->limit : ~((u32) 0));
}
static void
channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf)
{
channel_reset_limit(c, l, dir);
channel_update_limit(c, l, dir, cf);
}
static void
channel_reset_limit(struct channel *c, struct limit *l, int dir)
{
limit_reset(l);
c->limit_active &= ~(1 << dir);
} }
static inline void static inline void
@ -2017,12 +2032,16 @@ channel_show_stats(struct channel *c)
struct import_stats *is = &c->import_stats; struct import_stats *is = &c->import_stats;
struct export_stats *es = &c->export_stats; struct export_stats *es = &c->export_stats;
u32 rx_routes = c->rx_limit.count;
u32 in_routes = c->in_limit.count;
u32 out_routes = c->out_limit.count;
if (c->in_keep_filtered) if (c->in_keep_filtered)
cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred", cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred",
is->routes, is->filtered, es->routes, is->pref); in_routes, (rx_routes - in_routes), out_routes, is->pref);
else else
cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
is->routes, es->routes, is->pref); in_routes, out_routes, is->pref);
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
@ -2040,13 +2059,13 @@ channel_show_stats(struct channel *c)
} }
void void
channel_show_limit(struct channel_limit *l, const char *dsc) channel_show_limit(struct limit *l, const char *dsc, int active, int action)
{ {
if (!l->action) if (!l->action)
return; return;
cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : ""); cli_msg(-1006, " %-16s%d%s", dsc, l->max, active ? " [HIT]" : "");
cli_msg(-1006, " Action: %s", channel_limit_name(l)); cli_msg(-1006, " Action: %s", channel_limit_name[action]);
} }
void void
@ -2064,9 +2083,9 @@ channel_show_info(struct channel *c)
c->gr_lock ? " pending" : "", c->gr_lock ? " pending" : "",
c->gr_wait ? " waiting" : ""); c->gr_wait ? " waiting" : "");
channel_show_limit(&c->rx_limit, "Receive limit:"); channel_show_limit(&c->rx_limit, "Receive limit:", c->limit_active & (1 << PLD_RX), c->limit_actions[PLD_RX]);
channel_show_limit(&c->in_limit, "Import limit:"); channel_show_limit(&c->in_limit, "Import limit:", c->limit_active & (1 << PLD_IN), c->limit_actions[PLD_IN]);
channel_show_limit(&c->out_limit, "Export limit:"); channel_show_limit(&c->out_limit, "Export limit:", c->limit_active & (1 << PLD_OUT), c->limit_actions[PLD_OUT]);
if (c->channel_state != CS_DOWN) if (c->channel_state != CS_DOWN)
channel_show_stats(c); channel_show_stats(c);

View File

@ -13,6 +13,7 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/event.h" #include "lib/event.h"
#include "nest/route.h" #include "nest/route.h"
#include "nest/limit.h"
#include "conf/conf.h" #include "conf/conf.h"
struct iface; struct iface;
@ -134,8 +135,6 @@ struct proto_config {
/* Protocol statistics */ /* Protocol statistics */
struct import_stats { struct import_stats {
/* Import - from protocol to core */ /* 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 pref; /* Number of routes selected as best in the (adjacent) routing table */
u32 updates_received; /* Number of route updates received */ u32 updates_received; /* Number of route updates received */
u32 updates_invalid; /* Number of route updates rejected as invalid */ u32 updates_invalid; /* Number of route updates rejected as invalid */
@ -150,7 +149,6 @@ struct import_stats {
struct export_stats { struct export_stats {
/* Export - from core to protocol */ /* 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_received; /* Number of route updates received */
u32 updates_rejected; /* Number of route updates rejected by protocol */ u32 updates_rejected; /* Number of route updates rejected by protocol */
u32 updates_filtered; /* Number of route updates rejected by filters */ u32 updates_filtered; /* Number of route updates rejected by filters */
@ -277,7 +275,7 @@ void channel_graceful_restart_unlock(struct channel *c);
#define DEFAULT_GR_WAIT 240 #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_show_info(struct channel *c);
void channel_cmd_debug(struct channel *c, uint mask); void channel_cmd_debug(struct channel *c, uint mask);
@ -432,18 +430,29 @@ extern struct proto_config *cf_dev_proto;
#define PLA_RESTART 4 /* Force protocol restart */ #define PLA_RESTART 4 /* Force protocol restart */
#define PLA_DISABLE 5 /* Shutdown and disable protocol */ #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 { struct channel_limit {
u32 limit; /* Maximum number of prefixes */ u32 limit; /* Maximum number of prefixes */
u8 action; /* Action to take (PLA_*) */ 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 * Channels
@ -486,6 +495,7 @@ struct channel_config {
struct proto_config *parent; /* Where channel is defined (proto or template) */ struct proto_config *parent; /* Where channel is defined (proto or template) */
struct rtable_config *table; /* Table we're attached to */ struct rtable_config *table; /* Table we're attached to */
const struct filter *in_filter, *out_filter; /* Attached filters */ const struct filter *in_filter, *out_filter; /* Attached filters */
struct channel_limit rx_limit; /* Limit for receiving routes from protocol struct channel_limit rx_limit; /* Limit for receiving routes from protocol
(relevant when in_keep_filtered is active) */ (relevant when in_keep_filtered is active) */
struct channel_limit in_limit; /* Limit for importing routes from protocol */ struct channel_limit in_limit; /* Limit for importing routes from protocol */
@ -513,9 +523,13 @@ struct channel {
const struct filter *out_filter; /* Output filter */ const struct filter *out_filter; /* Output filter */
struct bmap export_map; /* Keeps track which routes were really exported */ 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 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 limit rx_limit; /* Receive limit (for in_keep_filtered) */
struct channel_limit out_limit; /* Output limit */ 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 event *feed_event; /* Event responsible for feeding */ struct event *feed_event; /* Event responsible for feeding */
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */ struct fib_iterator feed_fit; /* Routing table iterator used during feeding */

View File

@ -473,20 +473,16 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
if (refeed && new) if (refeed && new)
c->refeed_count++; c->refeed_count++;
/* Apply export limit */ if (!old && new)
struct channel_limit *l = &c->out_limit; if (CHANNEL_LIMIT_PUSH(c, OUT))
if (l->action && !old && new)
{
if (stats->routes >= l->limit)
channel_notify_limit(c, l, PLD_OUT, stats->routes);
if (l->state == PLS_BLOCKED)
{ {
stats->updates_rejected++; stats->updates_rejected++;
rte_trace_out(D_FILTERS, c, new, "rejected [limit]"); rte_trace_out(D_FILTERS, c, new, "rejected [limit]");
return; return;
} }
}
if (!new && old)
CHANNEL_LIMIT_POP(c, OUT);
/* Apply export table */ /* Apply export table */
struct rte_storage *old_exported = NULL; struct rte_storage *old_exported = NULL;
@ -505,16 +501,10 @@ do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int ref
stats->withdraws_accepted++; stats->withdraws_accepted++;
if (old) if (old)
{
bmap_clear(&c->export_map, old->id); bmap_clear(&c->export_map, old->id);
stats->routes--;
}
if (new) if (new)
{
bmap_set(&c->export_map, new->id); bmap_set(&c->export_map, new->id);
stats->routes++;
}
if (p->debug & D_ROUTES) if (p->debug & D_ROUTES)
{ {
@ -973,15 +963,10 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
int new_ok = rte_is_ok(new); int new_ok = rte_is_ok(new);
int old_ok = rte_is_ok(old); int old_ok = rte_is_ok(old);
struct channel_limit *l = &c->rx_limit; if (!c->in_table)
if (l->action && !old && new && !c->in_table)
{ {
u32 all_routes = stats->routes + stats->filtered; if (!old && new)
if (CHANNEL_LIMIT_PUSH(c, RX))
if (all_routes >= l->limit)
channel_notify_limit(c, l, PLD_RX, all_routes);
if (l->state == PLS_BLOCKED)
{ {
/* In receive limit the situation is simple, old is NULL so /* In receive limit the situation is simple, old is NULL so
we just free new and exit like nothing happened */ we just free new and exit like nothing happened */
@ -990,15 +975,13 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
rte_trace_in(D_FILTERS, c, new, "ignored [limit]"); rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
return; return;
} }
if (old && !new)
CHANNEL_LIMIT_POP(c, RX);
} }
l = &c->in_limit; if (!old_ok && new_ok)
if (l->action && !old_ok && new_ok) if (CHANNEL_LIMIT_PUSH(c, IN))
{
if (stats->routes >= l->limit)
channel_notify_limit(c, l, PLD_IN, stats->routes);
if (l->state == PLS_BLOCKED)
{ {
/* In import limit the situation is more complicated. We /* In import limit the situation is more complicated. We
shouldn't just drop the route, we should handle it like shouldn't just drop the route, we should handle it like
@ -1024,7 +1007,9 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
new_ok = 0; new_ok = 0;
goto skip_stats1; goto skip_stats1;
} }
}
if (old_ok && !new_ok)
CHANNEL_LIMIT_POP(c, IN);
if (new_ok) if (new_ok)
stats->updates_accepted++; stats->updates_accepted++;
@ -1039,11 +1024,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
skip_stats1:; skip_stats1:;
struct rte_storage *new_stored = new ? rte_store(new, net, table) : NULL; struct rte_storage *new_stored = new ? rte_store(new, net, table) : NULL;
if (new)
rte_is_filtered(new) ? stats->filtered++ : stats->routes++;
if (old)
rte_is_filtered(old) ? stats->filtered-- : stats->routes--;
if (table->config->sorted) if (table->config->sorted)
{ {
/* If routes are sorted, just insert new route to appropriate position */ /* If routes are sorted, just insert new route to appropriate position */
@ -2332,6 +2312,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
goto drop_update; goto drop_update;
} }
if (!new)
CHANNEL_LIMIT_POP(c, RX);
/* Move iterator if needed */ /* Move iterator if needed */
if (*pos == c->reload_next_rte) if (*pos == c->reload_next_rte)
c->reload_next_rte = (*pos)->next; c->reload_next_rte = (*pos)->next;
@ -2342,7 +2325,18 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
rte_free(del, tab); rte_free(del, tab);
tab->rt_count--; tab->rt_count--;
} }
else if (!new) else if (new)
{
if (CHANNEL_LIMIT_PUSH(c, RX))
{
/* Required by rte_trace_in() */
new->net = n;
rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
goto drop_update;
}
}
else
goto drop_withdraw; goto drop_withdraw;
if (!new) if (!new)
@ -2353,22 +2347,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
return 1; return 1;
} }
struct channel_limit *l = &c->rx_limit;
if (l->action && !*pos)
{
if (tab->rt_count >= l->limit)
channel_notify_limit(c, l, PLD_RX, tab->rt_count);
if (l->state == PLS_BLOCKED)
{
/* Required by rte_trace_in() */
new->net = n;
rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
goto drop_update;
}
}
/* Insert the new rte */ /* Insert the new rte */
struct rte_storage *e = rte_store(new, net, tab); struct rte_storage *e = rte_store(new, net, tab);
e->rte.sender = c; e->rte.sender = c;

View File

@ -217,6 +217,9 @@ pipe_show_stats(struct pipe_proto *p)
struct import_stats *s2i = &p->sec->import_stats; struct import_stats *s2i = &p->sec->import_stats;
struct export_stats *s2e = &p->sec->export_stats; struct export_stats *s2e = &p->sec->export_stats;
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 * Pipe stats (as anything related to pipes) are a bit tricky. There
* are two sets of stats - s1 for ahook to the primary routing and * are two sets of stats - s1 for ahook to the primary routing and
@ -239,7 +242,7 @@ pipe_show_stats(struct pipe_proto *p)
*/ */
cli_msg(-1006, " Routes: %u imported, %u exported", 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, " Route change stats: received rejected filtered ignored accepted");
cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
s2e->updates_received, s2e->updates_rejected + s1i->updates_invalid, s2e->updates_received, s2e->updates_rejected + s1i->updates_invalid,
@ -270,8 +273,12 @@ pipe_show_proto_info(struct proto *P)
cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter));
cli_msg(-1006, " Export filter: %s", filter_name(p->pri->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) if (P->proto_state != PS_DOWN)
pipe_show_stats(p); pipe_show_stats(p);