summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nest/proto.c45
-rw-r--r--nest/protocol.h15
-rw-r--r--nest/rt-table.c16
-rw-r--r--proto/bgp/bgp.c4
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/pipe/pipe.c8
-rw-r--r--sysdep/linux/netlink/netlink.c14
7 files changed, 59 insertions, 44 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 418a7a61..cf81573f 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -785,7 +785,9 @@ proto_schedule_feed(struct proto *p, int initial)
p->main_ahook->in_filter = p->cf->in_filter;
p->main_ahook->out_filter = p->cf->out_filter;
p->main_ahook->in_limit = p->cf->in_limit;
+ proto_reset_limit(p->main_ahook->in_limit);
// p->main_ahook->out_limit = p->cf->out_limit;
+ // proto_reset_limit(p->main_ahook->out_limit);
}
proto_relink(p);
@@ -953,43 +955,42 @@ proto_limit_name(struct proto_limit *l)
* proto_notify_limit: notify about limit hit and take appropriate action
* @ah: announce hook
* @l: limit being hit
+ * @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. It also says what should be done with the
- * route that breached the limit.
- *
- * Returns 1 if the route should be freed, 0 otherwise.
+ * according to @l->action.
*/
-int
-proto_notify_limit(struct announce_hook *ah, struct proto_limit *l)
+void
+proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count)
{
struct proto *p = ah->proto;
int dir = (ah->in_limit == l);
- if (l->active)
- return (l->action != PLA_WARN);
+ if (l->state == PLS_BLOCKED)
+ return;
- l->active = 1;
- log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
- p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));
+ if (rt_count == l->limit)
+ log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
+ p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));
switch (l->action)
{
case PLA_WARN:
- return 0;
+ l->state = PLS_ACTIVE;
+ break;
case PLA_BLOCK:
- return 1;
+ l->state = PLS_BLOCKED;
+ break;
case PLA_RESTART:
case PLA_DISABLE:
+ l->state = PLS_BLOCKED;
proto_schedule_down(p, l->action == PLA_RESTART,
dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT);
- return 1;
+ break;
}
-
- return 0;
}
/**
@@ -1101,9 +1102,11 @@ proto_show_stats(struct proto_stats *s)
void
proto_show_limit(struct proto_limit *l, const char *dsc)
{
- if (l)
- cli_msg(-1006, " %16s%d, action: %s%s", dsc, l->limit,
- proto_limit_name(l), l->active ? " [HIT]" : "");
+ if (!l)
+ return;
+
+ cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
+ cli_msg(-1006, " Action: %s", proto_limit_name(l));
}
void
@@ -1233,8 +1236,8 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
* Should be done before reload_routes() hook?
* Perhaps, but these hooks work asynchronously.
*/
- if (!p->proto->multitable && p->main_ahook->in_limit)
- p->main_ahook->in_limit->active = 0;
+ if (!p->proto->multitable)
+ proto_reset_limit(p->main_ahook->in_limit);
}
/* re-exporting routes */
diff --git a/nest/protocol.h b/nest/protocol.h
index 3dd7cf2f..d8442acb 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -375,13 +375,24 @@ 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 proto_limit {
u32 limit; /* Maximum number of prefixes */
byte action; /* Action to take (PLA_*) */
- byte active; /* Limit is active */
+ byte state; /* State of limit (PLS_*) */
};
-int proto_notify_limit(struct announce_hook *ah, struct proto_limit *l);
+void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count);
+
+static inline void proto_reset_limit(struct proto_limit *l)
+{
+ if (l)
+ l->state = PLS_INITIAL;
+}
+
/*
* Route Announcement Hook
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 6a28fd43..6d82e1d3 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -485,12 +485,18 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
}
struct proto_limit *l = ah->in_limit;
- if (l && !old && new && (stats->imp_routes >= l->limit) && proto_notify_limit(ah, l))
+ if (l && !old && new)
{
- stats->imp_updates_ignored++;
- rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
- rte_free_quick(new);
- return;
+ if (stats->imp_routes >= l->limit)
+ proto_notify_limit(ah, l, stats->imp_routes);
+
+ if (l->state == PLS_BLOCKED)
+ {
+ stats->imp_updates_ignored++;
+ rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
+ rte_free_quick(new);
+ return;
+ }
}
if (new)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index cf743dff..95dbe477 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -1165,9 +1165,9 @@ bgp_show_proto_info(struct proto *P)
p->rs_client ? " route-server" : "",
p->as4_session ? " AS4" : "");
cli_msg(-1006, " Source address: %I", p->source_addr);
- if (p->cf->route_limit)
+ if (P->cf->in_limit)
cli_msg(-1006, " Route limit: %d/%d",
- p->p.stats.imp_routes, p->cf->route_limit);
+ p->p.stats.imp_routes, P->cf->in_limit->limit);
cli_msg(-1006, " Hold timer: %d/%d",
tm_remains(c->hold_timer), c->hold_time);
cli_msg(-1006, " Keepalive timer: %d/%d",
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index aa2db4b0..1c16f485 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -40,7 +40,6 @@ struct bgp_config {
int rr_client; /* Whether neighbor is RR client of me */
int rs_client; /* Whether neighbor is RS client of me */
int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */
- u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */
int passive; /* Do not initiate outgoing connection */
int interpret_communities; /* Hardwired handling of well-known communities */
unsigned connect_retry_time;
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index a5fcc6f6..41bac474 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -127,10 +127,8 @@ pipe_reload_routes(struct proto *P)
*/
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;
+ proto_reset_limit(P->main_ahook->in_limit);
+ proto_reset_limit(p->peer_ahook->in_limit);
return 1;
}
@@ -168,10 +166,12 @@ pipe_start(struct proto *P)
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;
+ proto_reset_limit(P->main_ahook->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;
+ proto_reset_limit(p->peer_ahook->in_limit);
return PS_UP;
}
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c
index d9d22d4c..182088a1 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink/netlink.c
@@ -588,9 +588,9 @@ krt_capable(rte *e)
switch (a->dest)
{
case RTD_ROUTER:
- if (ipa_has_link_scope(a->gw) && (a->iface == NULL))
- return 0;
case RTD_DEVICE:
+ if (a->iface == NULL)
+ return 0;
case RTD_BLACKHOLE:
case RTD_UNREACHABLE:
case RTD_PROHIBIT:
@@ -653,20 +653,16 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
if (ea = ea_find(eattrs, EA_KRT_REALM))
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
+ /* a->iface != NULL checked in krt_capable() for router and device routes */
+
switch (a->dest)
{
case RTD_ROUTER:
r.r.rtm_type = RTN_UNICAST;
+ nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
-
- /* a->iface != NULL checked in krt_capable() */
- if (ipa_has_link_scope(a->gw))
- nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
-
break;
case RTD_DEVICE:
- if (!a->iface)
- return -1;
r.r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
break;