summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/bgp.c63
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/bgp/config.Y6
-rw-r--r--proto/bgp/packets.c3
-rw-r--r--proto/pipe/config.Y1
-rw-r--r--proto/pipe/pipe.c45
-rw-r--r--proto/pipe/pipe.h1
7 files changed, 76 insertions, 44 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 4dd4b7be..cf743dff 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -542,22 +542,6 @@ bgp_active(struct bgp_proto *p)
bgp_start_timer(conn->connect_retry_timer, delay);
}
-int
-bgp_apply_limits(struct bgp_proto *p)
-{
- if (p->cf->route_limit && (p->p.stats.imp_routes > p->cf->route_limit))
- {
- log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
- bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
- bgp_update_startup_delay(p);
- bgp_stop(p, 1); // Errcode 6, 1 - max number of prefixes reached
- return -1;
- }
-
- return 0;
-}
-
-
/**
* bgp_connect - initiate an outgoing connection
* @p: BGP instance
@@ -868,24 +852,46 @@ static int
bgp_shutdown(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
- unsigned subcode;
+ unsigned subcode = 0;
BGP_TRACE(D_EVENTS, "Shutdown requested");
- bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
- if (P->reconfiguring)
+ switch (P->down_code)
{
- if (P->cf_new)
- subcode = 6; // Errcode 6, 6 - other configuration change
+ case PDC_CF_REMOVE:
+ case PDC_CF_DISABLE:
+ subcode = 3; // Errcode 6, 3 - peer de-configured
+ break;
+
+ case PDC_CF_RESTART:
+ subcode = 6; // Errcode 6, 6 - other configuration change
+ break;
+
+ case PDC_CMD_DISABLE:
+ subcode = 2; // Errcode 6, 2 - administrative shutdown
+ break;
+
+ case PDC_CMD_RESTART:
+ subcode = 4; // Errcode 6, 4 - administrative reset
+ break;
+
+ case PDC_IN_LIMIT_HIT:
+ subcode = 1; // Errcode 6, 1 - max number of prefixes reached
+ log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
+
+ bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
+ if (P->cf->in_limit->action == PLA_RESTART)
+ bgp_update_startup_delay(p);
else
- subcode = 3; // Errcode 6, 3 - peer de-configured
+ p->startup_delay = 0;
+ goto done;
}
- else
- subcode = 2; // Errcode 6, 2 - administrative shutdown
+ bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 0;
- bgp_stop(p, subcode);
+ done:
+ bgp_stop(p, subcode);
return p->p.proto_state;
}
@@ -969,6 +975,10 @@ bgp_check_config(struct bgp_config *c)
/* Different default for gw_mode */
if (!c->gw_mode)
c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
+
+ /* Disable after error incompatible with restart limit action */
+ if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error)
+ c->c.in_limit->action = PLA_DISABLE;
}
static int
@@ -1116,9 +1126,6 @@ bgp_get_status(struct proto *P, byte *buf)
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
}
-static inline bird_clock_t tm_remains(timer *t)
-{ return t->expires ? t->expires - now : 0; }
-
static void
bgp_show_proto_info(struct proto *P)
{
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index a8c5818e..aa2db4b0 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -152,7 +152,6 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn);
void bgp_conn_enter_close_state(struct bgp_conn *conn);
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
-int bgp_apply_limits(struct bgp_proto *p);
void bgp_stop(struct bgp_proto *p, unsigned subcode);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 78ca52de..5feaea0d 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -98,7 +98,11 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
- | bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
+ | bgp_proto ROUTE LIMIT expr ';' {
+ this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
+ this_proto->in_limit->limit = $4;
+ this_proto->in_limit->action = PLA_RESTART;
+ }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index d3e9b6a1..168025d0 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -915,9 +915,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
-
- if (bgp_apply_limits(p) < 0)
- goto done;
}
done:
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 40637558..4fb2b499 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -36,6 +36,7 @@ pipe_proto:
cf_error("Routing table name expected");
PIPE_CFG->peer = $4->def;
}
+ | pipe_proto EXPORT LIMIT limit_spec ';' { PIPE_CFG->out_limit = $4; }
| pipe_proto MODE OPAQUE ';' { PIPE_CFG->mode = PIPE_OPAQUE; }
| pipe_proto MODE TRANSPARENT ';' { PIPE_CFG->mode = PIPE_TRANSPARENT; }
;
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 36b06d43..a5fcc6f6 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -24,9 +24,10 @@
* rte_update(), an import filter in ahook 2 is called. When a new
* route is announced in the peer table, an export filter in ahook2
* and an import filter in ahook 1 are used. Oviously, there is no
- * need in filtering the same route twice, so both import filters
- * are set to accept, while user configured 'import' and 'export'
- * filters are used as export filters in ahooks 2 and 1.
+ * need in filtering the same route twice, so both import filters are
+ * set to accept, while user configured 'import' and 'export' filters
+ * are used as export filters in ahooks 2 and 1. Route limits are
+ * handled similarly, but on the import side of ahooks.
*/
#undef LOCAL_DEBUG
@@ -116,6 +117,8 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo
static int
pipe_reload_routes(struct proto *P)
{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+
/*
* Because the pipe protocol feeds routes from both routing tables
* together, both directions are reloaded during refeed and 'reload
@@ -123,6 +126,12 @@ pipe_reload_routes(struct proto *P)
* request refeed when 'reload in' command is used.
*/
proto_request_feeding(P);
+
+ if (P->main_ahook->in_limit)
+ P->main_ahook->in_limit->active = 0;
+ if (p->peer_ahook->in_limit)
+ p->peer_ahook->in_limit->active = 0;
+
return 1;
}
@@ -146,6 +155,7 @@ pipe_init(struct proto_config *C)
static int
pipe_start(struct proto *P)
{
+ struct pipe_config *cf = (struct pipe_config *) P->cf;
struct pipe_proto *p = (struct pipe_proto *) P;
/* Lock both tables, unlock is handled in pipe_cleanup() */
@@ -155,10 +165,13 @@ pipe_start(struct proto *P)
/* Going directly to PS_UP - prepare for feeding,
connect the protocol to both routing tables */
- P->main_ahook = proto_add_announce_hook(P, P->table,
- FILTER_ACCEPT, P->cf->out_filter, &P->stats);
- p->peer_ahook = proto_add_announce_hook(P, p->peer_table,
- FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats);
+ P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
+ P->main_ahook->out_filter = cf->c.out_filter;
+ P->main_ahook->in_limit = cf->c.in_limit;
+
+ p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
+ p->peer_ahook->out_filter = cf->c.in_filter;
+ p->peer_ahook->in_limit = cf->out_limit;
return PS_UP;
}
@@ -204,10 +217,16 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
/* Update output filters in ahooks */
if (P->main_ahook)
- P->main_ahook->out_filter = new->out_filter;
+ {
+ P->main_ahook->out_filter = new->out_filter;
+ P->main_ahook->in_limit = new->in_limit;
+ }
if (p->peer_ahook)
- p->peer_ahook->out_filter = new->in_filter;
+ {
+ p->peer_ahook->out_filter = new->in_filter;
+ p->peer_ahook->in_limit = nc->out_limit;
+ }
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
return 1;
@@ -283,12 +302,16 @@ static void
pipe_show_proto_info(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
+ struct pipe_config *cf = (struct pipe_config *) P->cf;
// cli_msg(-1006, " Table: %s", P->table->name);
// cli_msg(-1006, " Peer table: %s", p->peer_table->name);
cli_msg(-1006, " Preference: %d", P->preference);
- cli_msg(-1006, " Input filter: %s", filter_name(P->cf->in_filter));
- cli_msg(-1006, " Output filter: %s", filter_name(P->cf->out_filter));
+ cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter));
+ cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter));
+
+ proto_show_limit(cf->c.in_limit, "Import limit:");
+ proto_show_limit(cf->out_limit, "Export limit:");
if (P->proto_state != PS_DOWN)
pipe_show_stats(p);
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index 50b31698..e777fb41 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -15,6 +15,7 @@
struct pipe_config {
struct proto_config c;
struct rtable_config *peer; /* Table we're connected to */
+ struct proto_limit *out_limit; /* Export route limit */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
};