summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
Diffstat (limited to 'proto')
-rw-r--r--proto/babel/babel.c48
-rw-r--r--proto/babel/packets.c2
-rw-r--r--proto/bfd/bfd.c31
-rw-r--r--proto/bfd/bfd.h3
-rw-r--r--proto/bfd/config.Y4
-rw-r--r--proto/bfd/packets.c36
-rw-r--r--proto/bgp/attrs.c109
-rw-r--r--proto/bgp/bgp.c27
-rw-r--r--proto/bgp/bgp.h16
-rw-r--r--proto/bgp/packets.c13
-rw-r--r--proto/mrt/mrt.c21
-rw-r--r--proto/ospf/ospf.c8
-rw-r--r--proto/ospf/rt.c16
-rw-r--r--proto/ospf/topology.c12
-rw-r--r--proto/ospf/topology.h2
-rw-r--r--proto/perf/perf.c13
-rw-r--r--proto/pipe/config.Y7
-rw-r--r--proto/pipe/pipe.c108
-rw-r--r--proto/pipe/pipe.h2
-rw-r--r--proto/radv/radv.c18
-rw-r--r--proto/rip/rip.c25
-rw-r--r--proto/rpki/packets.c19
-rw-r--r--proto/rpki/rpki.c33
-rw-r--r--proto/rpki/transport.c1
-rw-r--r--proto/static/static.c34
25 files changed, 349 insertions, 259 deletions
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index a6cc7aa3..6df80922 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -681,11 +681,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
if (!neigh_find(&p->p, r->next_hop, r->neigh->ifa->iface, 0))
a0.nh.flags = RNF_ONLINK;
- rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a, p->p.main_source);
+ rte e0 = {
+ .attrs = &a0,
+ .src = p->p.main_source,
+ };
e->unreachable = 0;
- rte_update2(c, e->n.addr, rte, p->p.main_source);
+ rte_update(c, e->n.addr, &e0, p->p.main_source);
}
else if (e->valid && (e->router_id != p->router_id))
{
@@ -697,18 +699,19 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.pref = 1,
};
- rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a, p->p.main_source);
- rte->pflags = 0;
+ rte e0 = {
+ .attrs = &a0,
+ .src = p->p.main_source,
+ };
e->unreachable = 1;
- rte_update2(c, e->n.addr, rte, p->p.main_source);
+ rte_update(c, e->n.addr, &e0, p->p.main_source);
}
else
{
/* Retraction */
e->unreachable = 0;
- rte_update2(c, e->n.addr, NULL, p->p.main_source);
+ rte_update(c, e->n.addr, NULL, p->p.main_source);
}
}
@@ -718,7 +721,7 @@ babel_announce_retraction(struct babel_proto *p, struct babel_entry *e)
{
struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
e->unreachable = 0;
- rte_update2(c, e->n.addr, NULL, p->p.main_source);
+ rte_update(c, e->n.addr, NULL, p->p.main_source);
}
@@ -859,14 +862,14 @@ babel_send_ihus(struct babel_iface *ifa)
}
static void
-babel_send_hello(struct babel_iface *ifa)
+babel_send_hello(struct babel_iface *ifa, uint interval)
{
struct babel_proto *p = ifa->proto;
union babel_msg msg = {};
msg.type = BABEL_TLV_HELLO;
msg.hello.seqno = ifa->hello_seqno++;
- msg.hello.interval = ifa->cf->hello_interval;
+ msg.hello.interval = interval ?: ifa->cf->hello_interval;
TRACE(D_PACKETS, "Sending hello on %s with seqno %d interval %t",
ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval);
@@ -1574,7 +1577,7 @@ babel_iface_timer(timer *t)
if (now_ >= ifa->next_hello)
{
- babel_send_hello(ifa);
+ babel_send_hello(ifa, 0);
ifa->next_hello += hello_period * (1 + (now_ - ifa->next_hello) / hello_period);
}
@@ -1621,7 +1624,7 @@ babel_iface_start(struct babel_iface *ifa)
tm_start(ifa->timer, 100 MS);
ifa->up = 1;
- babel_send_hello(ifa);
+ babel_send_hello(ifa, 0);
babel_send_wildcard_retraction(ifa);
babel_send_wildcard_request(ifa);
babel_send_update(ifa, 0); /* Full update */
@@ -2257,11 +2260,11 @@ babel_kick_timer(struct babel_proto *p)
static int
-babel_preexport(struct proto *P, struct rte *new)
+babel_preexport(struct channel *c, struct rte *new)
{
struct rta *a = new->attrs;
/* Reject our own unreachable routes */
- if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
+ if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto))
return -1;
return 0;
@@ -2272,8 +2275,8 @@ babel_preexport(struct proto *P, struct rte *new)
* so store it into our data structures.
*/
static void
-babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
- struct rte *new, struct rte *old UNUSED)
+babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
+ struct rte *new, const struct rte *old UNUSED)
{
struct babel_proto *p = (void *) P;
struct babel_entry *e;
@@ -2301,11 +2304,11 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
if (rt_metric > BABEL_INFINITY)
{
log(L_WARN "%s: Invalid babel_metric value %u for route %N",
- p->p.name, rt_metric, net->n.addr);
+ p->p.name, rt_metric, net);
rt_metric = BABEL_INFINITY;
}
- e = babel_get_entry(p, net->n.addr);
+ e = babel_get_entry(p, net);
/* Activate triggered updates */
if ((e->valid != BABEL_ENTRY_VALID) ||
@@ -2323,7 +2326,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
else
{
/* Withdraw */
- e = babel_find_entry(p, net->n.addr);
+ e = babel_find_entry(p, net);
if (!e || e->valid != BABEL_ENTRY_VALID)
return;
@@ -2432,6 +2435,11 @@ babel_iface_shutdown(struct babel_iface *ifa)
{
if (ifa->sk)
{
+ /*
+ * Retract all our routes and lower the hello interval so peers' neighbour
+ * state expires quickly
+ */
+ babel_send_hello(ifa, BABEL_MIN_INTERVAL);
babel_send_wildcard_retraction(ifa);
babel_send_queue(ifa);
}
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index 2a6d443d..d4acc170 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -2010,7 +2010,7 @@ babel_auth_sign(struct babel_iface *ifa, ip_addr dest)
}
DBG("Added MAC signatures (%d bytes) on ifa %s for dest %I\n",
- tot_len, ifa->ifname, dest);
+ pos - (pkt + len), ifa->ifname, dest);
return pos - (pkt + len);
}
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index d1e97cd5..873e2ed5 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -582,6 +582,9 @@ bfd_get_iface(struct bfd_proto *p, ip_addr local, struct iface *iface)
ifa->sk = bfd_open_tx_sk(p, local, iface);
ifa->uc = 1;
+ if (cf->strict_bind)
+ ifa->rx = bfd_open_rx_sk_bound(p, local, iface);
+
add_tail(&p->iface_list, &ifa->n);
return ifa;
@@ -599,6 +602,12 @@ bfd_free_iface(struct bfd_iface *ifa)
rfree(ifa->sk);
}
+ if (ifa->rx)
+ {
+ sk_stop(ifa->rx);
+ rfree(ifa->rx);
+ }
+
rem_node(&ifa->n);
mb_free(ifa);
}
@@ -1031,17 +1040,20 @@ bfd_start(struct proto *P)
birdloop_enter(p->loop);
- if (cf->accept_ipv4 && cf->accept_direct)
- p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
+ if (!cf->strict_bind)
+ {
+ if (cf->accept_ipv4 && cf->accept_direct)
+ p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
- if (cf->accept_ipv4 && cf->accept_multihop)
- p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
+ if (cf->accept_ipv4 && cf->accept_multihop)
+ p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
- if (cf->accept_ipv6 && cf->accept_direct)
- p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
+ if (cf->accept_ipv6 && cf->accept_direct)
+ p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
- if (cf->accept_ipv6 && cf->accept_multihop)
- p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
+ if (cf->accept_ipv6 && cf->accept_multihop)
+ p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
+ }
birdloop_leave(p->loop);
@@ -1095,7 +1107,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
if ((new->accept_ipv4 != old->accept_ipv4) ||
(new->accept_ipv6 != old->accept_ipv6) ||
(new->accept_direct != old->accept_direct) ||
- (new->accept_multihop != old->accept_multihop))
+ (new->accept_multihop != old->accept_multihop) ||
+ (new->strict_bind != old->strict_bind))
return 0;
birdloop_mask_wakeups(p->loop);
diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h
index bbccd0b8..60b7916c 100644
--- a/proto/bfd/bfd.h
+++ b/proto/bfd/bfd.h
@@ -47,6 +47,7 @@ struct bfd_config
u8 accept_ipv6;
u8 accept_direct;
u8 accept_multihop;
+ u8 strict_bind;
};
struct bfd_iface_config
@@ -116,6 +117,7 @@ struct bfd_iface
struct bfd_proto *bfd;
sock *sk;
+ sock *rx;
u32 uc;
u8 changed;
};
@@ -221,6 +223,7 @@ void bfd_show_sessions(struct proto *P);
/* packets.c */
void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final);
sock * bfd_open_rx_sk(struct bfd_proto *p, int multihop, int inet_version);
+sock * bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa);
sock * bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa);
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index df1cba42..70461872 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -23,7 +23,8 @@ CF_DECLS
CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION,
- NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT)
+ NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT,
+ STRICT, BIND)
%type <iface> bfd_neigh_iface
%type <a> bfd_neigh_local
@@ -48,6 +49,7 @@ bfd_proto_item:
| INTERFACE bfd_iface
| MULTIHOP bfd_multihop
| NEIGHBOR bfd_neighbor
+ | STRICT BIND bool { BFD_CFG->strict_bind = $3; }
;
bfd_proto_opts:
diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c
index 7618e20f..5f10734c 100644
--- a/proto/bfd/packets.c
+++ b/proto/bfd/packets.c
@@ -366,7 +366,9 @@ bfd_rx_hook(sock *sk, uint len)
if (ps > BFD_STATE_DOWN)
DROP("invalid init state", ps);
- uint ifindex = (sk->sport == BFD_CONTROL_PORT) ? sk->lifindex : 0;
+ uint ifindex = (sk->sport == BFD_CONTROL_PORT) ?
+ (sk->iface ? sk->iface->index : sk->lifindex) :
+ 0;
s = bfd_find_session_by_addr(p, sk->faddr, ifindex);
/* FIXME: better session matching and message */
@@ -439,6 +441,38 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af)
}
sock *
+bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa)
+{
+ sock *sk = sk_new(p->tpool);
+ sk->type = SK_UDP;
+ sk->saddr = local;
+ sk->sport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
+ sk->iface = ifa;
+ sk->vrf = p->p.vrf;
+ sk->data = p;
+
+ sk->rbsize = BFD_MAX_LEN;
+ sk->rx_hook = bfd_rx_hook;
+ sk->err_hook = bfd_err_hook;
+
+ /* TODO: configurable ToS and priority */
+ sk->tos = IP_PREC_INTERNET_CONTROL;
+ sk->priority = sk_priority_control;
+ sk->flags = SKF_THREAD | SKF_BIND | (ifa ? SKF_TTL_RX : 0);
+
+ if (sk_open(sk) < 0)
+ goto err;
+
+ sk_start(sk);
+ return sk;
+
+ err:
+ sk_log_error(sk, p->p.name);
+ rfree(sk);
+ return NULL;
+}
+
+sock *
bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
{
sock *sk = sk_new(p->tpool);
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 2c0d011f..1cd2bcca 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -336,26 +336,26 @@ bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric)
}
int
-bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad)
+bgp_total_aigp_metric_(struct rta *a, u64 *metric, const struct adata **ad)
{
- eattr *a = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
- if (!a)
+ eattr *ea = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
+ if (!ea)
return 0;
- const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
+ const byte *b = bgp_aigp_get_tlv(ea->u.ptr, BGP_AIGP_METRIC);
if (!b)
return 0;
u64 aigp = get_u64(b + 3);
- u64 step = e->attrs->igp_metric;
+ u64 step = a->igp_metric;
- if (!rte_resolvable(e) || (step >= IGP_METRIC_UNKNOWN))
+ if (!rta_resolvable(a) || (step >= IGP_METRIC_UNKNOWN))
step = BGP_AIGP_MAX;
if (!step)
step = 1;
- *ad = a->u.ptr;
+ *ad = ea->u.ptr;
*metric = aigp + step;
if (*metric < aigp)
*metric = BGP_AIGP_MAX;
@@ -377,7 +377,7 @@ bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad)
u32
bgp_rte_igp_metric(struct rte *rt)
{
- u64 metric = bgp_total_aigp_metric(rt);
+ u64 metric = bgp_total_aigp_metric(rt->attrs);
return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN);
}
@@ -906,7 +906,7 @@ bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint fla
static void
bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
{
- net_addr *n = s->route->net->n.addr;
+ const net_addr *n = s->route->net;
u32 *labels = (u32 *) a->u.ptr->data;
uint lnum = a->u.ptr->length / 4;
@@ -1465,7 +1465,7 @@ bgp_finish_attrs(struct bgp_parse_state *s, rta *a)
#define RBH_FN(a,h) h
#define RBH_REHASH bgp_rbh_rehash
-#define RBH_PARAMS /8, *2, 2, 2, 8, 20
+#define RBH_PARAMS /8, *2, 2, 2, 12, 20
HASH_DEFINE_REHASH_FN(RBH, struct bgp_bucket)
@@ -1607,7 +1607,7 @@ bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b)
#define PXH_FN(n,i,h) h
#define PXH_REHASH bgp_pxh_rehash
-#define PXH_PARAMS /8, *2, 2, 2, 8, 24
+#define PXH_PARAMS /8, *2, 2, 2, 12, 24
HASH_DEFINE_REHASH_FN(PXH, struct bgp_prefix)
@@ -1631,9 +1631,10 @@ bgp_free_prefix_table(struct bgp_channel *c)
}
static struct bgp_prefix *
-bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
+bgp_get_prefix(struct bgp_channel *c, const net_addr *net, u32 path_id)
{
- u32 hash = net_hash(net) ^ u32_hash(path_id);
+ /* We must use a different hash function than the rtable */
+ u32 hash = u32_hash(net_hash(net) ^ u32_hash(path_id));
struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash);
if (px)
@@ -1675,10 +1676,10 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
*/
int
-bgp_preexport(struct proto *P, rte *e)
+bgp_preexport(struct channel *c, rte *e)
{
struct proto *SRC = e->src->proto;
- struct bgp_proto *p = (struct bgp_proto *) P;
+ struct bgp_proto *p = (struct bgp_proto *) (c->proto);
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
/* Reject our routes */
@@ -1690,8 +1691,8 @@ bgp_preexport(struct proto *P, rte *e)
return 0;
/* Reject flowspec that failed validation */
- if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
- return -1;
+ if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net))
+ return -1;
/* IBGP route reflection, RFC 4456 */
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
@@ -1707,11 +1708,11 @@ bgp_preexport(struct proto *P, rte *e)
}
/* Handle well-known communities, RFC 1997 */
- struct eattr *c;
+ struct eattr *com;
if (p->cf->interpret_communities &&
- (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
+ (com = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
{
- const struct adata *d = c->u.ptr;
+ const struct adata *d = com->u.ptr;
/* Do not export anywhere */
if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
@@ -1791,7 +1792,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
/* AIGP attribute - accumulate local metric or originate new one */
u64 metric;
if (s.local_next_hop &&
- (bgp_total_aigp_metric_(e, &metric, &ad) ||
+ (bgp_total_aigp_metric_(e->attrs, &metric, &ad) ||
(c->cf->aigp_originate && bgp_init_aigp_metric(e, &metric, &ad))))
{
ad = bgp_aigp_set_metric(pool, ad, metric);
@@ -1850,7 +1851,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at
}
void
-bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
+bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old)
{
struct bgp_proto *p = (void *) P;
struct bgp_channel *c = (void *) C;
@@ -1864,7 +1865,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
/* Error during attribute processing */
if (!attrs)
- log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n->n.addr);
+ log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n);
/* If attributes are invalid, we fail back to withdraw */
buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
@@ -1876,7 +1877,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
path = old->src->global_id;
}
- px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
+ px = bgp_get_prefix(c, n, c->add_path_tx ? path : 0);
add_tail(&buck->prefixes, &px->buck_node);
bgp_schedule_packet(p->conn, c, PKT_UPDATE);
@@ -1937,8 +1938,8 @@ bgp_rte_better(rte *new, rte *old)
return 1;
/* RFC 4271 9.1.2.1. Route resolvability test */
- n = rte_resolvable(new);
- o = rte_resolvable(old);
+ n = rta_resolvable(new->attrs);
+ o = rta_resolvable(old->attrs);
if (n > o)
return 1;
if (n < o)
@@ -1963,8 +1964,8 @@ bgp_rte_better(rte *new, rte *old)
return 0;
/* RFC 7311 4.1 - Apply AIGP metric */
- u64 n2 = bgp_total_aigp_metric(new);
- u64 o2 = bgp_total_aigp_metric(old);
+ u64 n2 = bgp_total_aigp_metric(new->attrs);
+ u64 o2 = bgp_total_aigp_metric(old->attrs);
if (n2 < o2)
return 1;
if (n2 > o2)
@@ -2078,7 +2079,7 @@ bgp_rte_mergable(rte *pri, rte *sec)
return 0;
/* RFC 4271 9.1.2.1. Route resolvability test */
- if (rte_resolvable(pri) != rte_resolvable(sec))
+ if (rta_resolvable(pri->attrs) != rta_resolvable(sec->attrs))
return 0;
/* LLGR draft - depreference stale routes */
@@ -2151,16 +2152,15 @@ same_group(rte *r, u32 lpref, u32 lasn)
}
static inline int
-use_deterministic_med(rte *r)
+use_deterministic_med(struct rte_storage *r)
{
- struct proto *P = r->src->proto;
+ struct proto *P = r->rte.src->proto;
return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
}
int
bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
{
- rte *r, *s;
rte *key = new ? new : old;
u32 lpref = key->attrs->pref;
u32 lasn = bgp_get_neighbor(key);
@@ -2228,13 +2228,13 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
}
/* The default case - find a new best-in-group route */
- r = new; /* new may not be in the list */
- for (s=net->routes; rte_is_valid(s); s=s->next)
- if (use_deterministic_med(s) && same_group(s, lpref, lasn))
+ rte *r = new; /* new may not be in the list */
+ for (struct rte_storage *s = net->routes; rte_is_valid(RTE_OR_NULL(s)); s = s->next)
+ if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn))
{
- s->pflags |= BGP_REF_SUPPRESSED;
- if (!r || bgp_rte_better(s, r))
- r = s;
+ s->rte.pflags |= BGP_REF_SUPPRESSED;
+ if (!r || bgp_rte_better(&s->rte, r))
+ r = &s->rte;
}
/* Simple case - the last route in group disappears */
@@ -2246,10 +2246,10 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
new->pflags &= ~BGP_REF_SUPPRESSED;
/* Found all existing routes mergable with best-in-group */
- for (s=net->routes; rte_is_valid(s); s=s->next)
- if (use_deterministic_med(s) && same_group(s, lpref, lasn))
- if ((s != r) && bgp_rte_mergable(r, s))
- s->pflags &= ~BGP_REF_SUPPRESSED;
+ for (struct rte_storage *s = net->routes; rte_is_valid(RTE_OR_NULL(s)); s = s->next)
+ if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn))
+ if ((&s->rte != r) && bgp_rte_mergable(r, &s->rte))
+ s->rte.pflags &= ~BGP_REF_SUPPRESSED;
/* Found best-in-group */
r->pflags &= ~BGP_REF_SUPPRESSED;
@@ -2284,12 +2284,12 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
return !old_suppressed;
}
-struct rte *
+rte *
bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
{
- eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
- const struct adata *ad = a ? a->u.ptr : NULL;
- uint flags = a ? a->flags : BAF_PARTIAL;
+ eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
+ const struct adata *ad = ea ? ea->u.ptr : NULL;
+ uint flags = ea ? ea->flags : BAF_PARTIAL;
if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
return NULL;
@@ -2297,12 +2297,17 @@ bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
return r;
- r = rte_cow_rta(r, pool);
- bgp_set_attr_ptr(&(r->attrs->eattrs), pool, BA_COMMUNITY, flags,
+ rta *a = rta_do_cow(r->attrs, pool);
+
+ _Thread_local static rte e0;
+ e0 = *r;
+ e0.attrs = a;
+
+ bgp_set_attr_ptr(&(a->eattrs), pool, BA_COMMUNITY, flags,
int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
- r->pflags |= BGP_REF_STALE;
+ e0.pflags |= BGP_REF_STALE;
- return r;
+ return &e0;
}
@@ -2393,14 +2398,14 @@ bgp_get_route_info(rte *e, byte *buf)
if (rte_stale(e))
buf += bsprintf(buf, "s");
- u64 metric = bgp_total_aigp_metric(e);
+ u64 metric = bgp_total_aigp_metric(e->attrs);
if (metric < BGP_AIGP_MAX)
{
buf += bsprintf(buf, "/%lu", metric);
}
else if (e->attrs->igp_metric)
{
- if (!rte_resolvable(e))
+ if (!rta_resolvable(e->attrs))
buf += bsprintf(buf, "/-");
else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN)
buf += bsprintf(buf, "/?");
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index aec78a45..7c2ee642 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -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);
@@ -2467,6 +2467,9 @@ bgp_show_proto_info(struct proto *P)
else
cli_msg(-1006, " Neighbor address: %I%J", p->remote_ip, p->cf->iface);
+ if ((p->conn == &p->outgoing_conn) && (p->cf->remote_port != BGP_PORT))
+ cli_msg(-1006, " Neighbor port: %u", p->cf->remote_port);
+
cli_msg(-1006, " Neighbor AS: %u", p->remote_as);
cli_msg(-1006, " Local AS: %u", p->cf->local_as);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index d09a5c8f..0a4b14a8 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -518,9 +518,9 @@ struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
static inline int
-rte_resolvable(rte *rt)
+rta_resolvable(rta *a)
{
- return rt->attrs->dest != RTD_UNREACHABLE;
+ return a->dest != RTD_UNREACHABLE;
}
@@ -592,22 +592,22 @@ int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
u32 bgp_rte_igp_metric(struct rte *);
-void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
-int bgp_preexport(struct proto *, struct rte *);
+void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);
+int bgp_preexport(struct channel *, struct rte *);
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
-void bgp_get_route_info(struct rte *, byte *buf);
-int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
+void bgp_get_route_info(struct rte *, byte *);
+int bgp_total_aigp_metric_(rta *a, u64 *metric, const struct adata **ad);
#define BGP_AIGP_METRIC 1
#define BGP_AIGP_MAX U64(0xffffffffffffffff)
static inline u64
-bgp_total_aigp_metric(rte *r)
+bgp_total_aigp_metric(rta *a)
{
u64 metric = BGP_AIGP_MAX;
const struct adata *ad;
- bgp_total_aigp_metric_(r, &metric, &ad);
+ bgp_total_aigp_metric_(a, &metric, &ad);
return metric;
}
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 8eeae490..093daf35 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1376,7 +1376,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
REPORT("Invalid route %N withdrawn", n);
/* Route withdraw */
- rte_update3(&s->channel->c, n, NULL, s->last_src);
+ rte_update(&s->channel->c, n, NULL, s->last_src);
return;
}
@@ -1389,11 +1389,12 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
a0->eattrs = ea;
}
- rta *a = rta_clone(s->cached_rta);
- rte *e = rte_get_temp(a, s->last_src);
+ rte e0 = {
+ .attrs = s->cached_rta,
+ .src = s->last_src,
+ };
- e->pflags = 0;
- rte_update3(&s->channel->c, n, e, s->last_src);
+ rte_update(&s->channel->c, n, &e0, s->last_src);
}
static void
@@ -2741,7 +2742,7 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, uint len)
{
case BGP_RR_REQUEST:
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
- channel_request_feeding(&c->c);
+ rt_refeed_channel(&c->c);
break;
case BGP_RR_BEGIN:
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 321c6395..58b8b671 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -113,13 +113,13 @@ mrt_buffer_flush(buffer *b)
}
#define MRT_DEFINE_TYPE(S, T) \
- static inline void mrt_put_##S##_(buffer *b, T x) \
+ UNUSED static inline void mrt_put_##S##_(buffer *b, T x) \
{ \
put_##S(b->pos, x); \
b->pos += sizeof(T); \
} \
\
- static inline void mrt_put_##S(buffer *b, T x) \
+ UNUSED static inline void mrt_put_##S(buffer *b, T x) \
{ \
mrt_buffer_need(b, sizeof(T)); \
put_##S(b->pos, x); \
@@ -460,7 +460,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
return;
fail:
- mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
+ mrt_log(s, "Attribute list too long for %N", r->net);
}
#endif
@@ -512,24 +512,21 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
mrt_rib_table_header(s, n->n.addr);
- rte *rt, *rt0;
- for (rt0 = n->routes; rt = rt0; rt0 = rt0->next)
+ for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next)
{
- if (rte_is_filtered(rt))
+ if (rte_is_filtered(&rt->rte))
continue;
/* Skip routes that should be reported in the other phase */
- if (!s->always_add_path && (!rt->src->private_id != !s->add_path))
+ if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path))
{
s->want_add_path = 1;
continue;
}
- if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT)
- mrt_rib_table_entry(s, rt);
-
- if (rt != rt0)
- rte_free(rt);
+ rte e = rt->rte;
+ if (f_run(s->filter, &e, s->linpool, 0) <= F_ACCEPT)
+ mrt_rib_table_entry(s, &e);
lp_flush(s->linpool);
}
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index d8bcc838..ab77de02 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -107,7 +107,7 @@
#include <stdlib.h>
#include "ospf.h"
-static int ospf_preexport(struct proto *P, rte *new);
+static int ospf_preexport(struct channel *C, rte *new);
static void ospf_reload_routes(struct channel *C);
static int ospf_rte_better(struct rte *new, struct rte *old);
static u32 ospf_rte_igp_metric(struct rte *rt);
@@ -482,13 +482,13 @@ ospf_disp(timer * timer)
* import to the filters.
*/
static int
-ospf_preexport(struct proto *P, rte *e)
+ospf_preexport(struct channel *c, rte *e)
{
- struct ospf_proto *p = (struct ospf_proto *) P;
+ struct ospf_proto *p = (struct ospf_proto *) c->proto;
struct ospf_area *oa = ospf_main_area(p);
/* Reject our own routes */
- if (e->src->proto == P)
+ if (e->src->proto == c->proto)
return -1;
/* Do not export routes to stub areas */
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 8643f456..7cb541d4 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -2096,15 +2096,18 @@ again1:
.u.data = nf->n.rid,
};
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a, p->p.main_source);
-
rta_free(nf->old_rta);
- nf->old_rta = rta_clone(a);
+ nf->old_rta = rta_lookup(&a0);
+
+ rte e0 = {
+ .attrs = nf->old_rta,
+ .src = p->p.main_source,
+ };
DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
- rte_update(&p->p, nf->fn.addr, e);
+
+ rte_update(p->p.main_channel, nf->fn.addr, &e0, p->p.main_source);
}
}
else if (nf->old_rta)
@@ -2113,7 +2116,7 @@ again1:
rta_free(nf->old_rta);
nf->old_rta = NULL;
- rte_update(&p->p, nf->fn.addr, NULL);
+ rte_update(p->p.main_channel, nf->fn.addr, NULL, p->p.main_source);
}
/* Remove unused rt entry, some special entries are persistent */
@@ -2129,7 +2132,6 @@ again1:
}
FIB_ITERATE_END;
-
WALK_LIST(oa, p->area_list)
{
/* Cleanup ASBR hash tables */
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 9fe68264..24fdcc54 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1300,7 +1300,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
}
void
-ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
+ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED)
{
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */
@@ -1319,7 +1319,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
if (!new)
{
- nf = fib_find(&p->rtf, n->n.addr);
+ nf = fib_find(&p->rtf, n);
if (!nf || !nf->external_rte)
return;
@@ -1346,14 +1346,14 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
if (m1 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
- p->p.name, m1, n->n.addr);
+ p->p.name, m1, n);
m1 = LSINFINITY;
}
if (m2 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
- p->p.name, m2, n->n.addr);
+ p->p.name, m2, n);
m2 = LSINFINITY;
}
@@ -1377,12 +1377,12 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
if (ipa_zero(fwd))
{
log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
- p->p.name, n->n.addr);
+ p->p.name, n);
return;
}
}
- nf = fib_get(&p->rtf, n->n.addr);
+ nf = fib_get(&p->rtf, n);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
nf->external_rte = 1;
}
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 535d1f1b..c36d0b50 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -200,7 +200,7 @@ void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 d
void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn);
void ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa);
-void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old);
+void ospf_rt_notify(struct proto *P, struct channel *ch, const net_addr *n, rte *new, const rte *old);
void ospf_update_topology(struct ospf_proto *p);
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
diff --git a/proto/perf/perf.c b/proto/perf/perf.c
index dde7e473..6ebfe361 100644
--- a/proto/perf/perf.c
+++ b/proto/perf/perf.c
@@ -160,18 +160,17 @@ perf_loop(void *data)
clock_gettime(CLOCK_MONOTONIC, &ts_generated);
- for (uint i=0; i<N; i++) {
- rte *e = rte_get_temp(p->data[i].a, p->p.main_source);
- e->pflags = 0;
-
- rte_update(P, &(p->data[i].net), e);
+ for (uint i=0; i<N; i++)
+ {
+ rte e0 = { .attrs = p->data[i].a, .src = P->main_source, };
+ rte_update(P->main_channel, &(p->data[i].net), &e0, P->main_source);
}
clock_gettime(CLOCK_MONOTONIC, &ts_update);
if (!p->keep)
for (uint i=0; i<N; i++)
- rte_update(P, &(p->data[i].net), NULL);
+ rte_update(P->main_channel, &(p->data[i].net), NULL, P->main_source);
clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
@@ -204,7 +203,7 @@ perf_loop(void *data)
}
static void
-perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED)
+perf_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net UNUSED, struct rte *new UNUSED, const struct rte *old UNUSED)
{
struct perf_proto *p = (struct perf_proto *) P;
p->exp++;
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 1202c169..c869de9f 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -16,7 +16,7 @@ CF_DEFINES
CF_DECLS
-CF_KEYWORDS(PIPE, PEER, TABLE)
+CF_KEYWORDS(PIPE, PEER, TABLE, MAX, GENERATION)
CF_GRAMMAR
@@ -25,6 +25,7 @@ proto: pipe_proto '}' { this_channel = NULL; } ;
pipe_proto_start: proto_start PIPE
{
this_proto = proto_config_new(&proto_pipe, $1);
+ PIPE_CFG->max_generation = 16;
}
proto_name
{
@@ -41,6 +42,10 @@ pipe_proto:
| pipe_proto proto_item ';'
| pipe_proto channel_item_ ';'
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
+ | pipe_proto MAX GENERATION expr ';' {
+ if (($4 < 1) || ($4 > 254)) cf_error("Max generation must be in range 1..254, got %u", $4);
+ PIPE_CFG->max_generation = $4;
+ }
;
CF_CODE
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 483ece67..e8c69a0e 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -48,61 +48,53 @@
#endif
static void
-pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old)
+pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *new, const rte *old)
{
struct pipe_proto *p = (void *) P;
struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
- struct rte_src *src;
-
- rte *e;
- rta *a;
if (!new && !old)
return;
- if (dst->table->pipe_busy)
- {
- log(L_ERR "Pipe loop detected when sending %N to table %s",
- n->n.addr, dst->table->name);
- return;
- }
-
if (new)
{
- src = new->src;
-
- a = alloca(rta_size(new->attrs));
+ rta *a = alloca(rta_size(new->attrs));
memcpy(a, new->attrs, rta_size(new->attrs));
a->cached = 0;
a->hostentry = NULL;
- e = rte_get_temp(a, src);
- e->pflags = new->pflags;
-#ifdef CONFIG_BGP
- /* Hack to cleanup cached value */
- if (e->src->proto->proto == &proto_bgp)
- e->pflags &= ~(BGP_REF_STALE | BGP_REF_NOT_STALE);
-#endif
+ rte e0 = {
+ .attrs = a,
+ .src = new->src,
+ .generation = new->generation + 1,
+ };
+
+ rte_update(dst, n, &e0, new->src);
}
else
- {
- e = NULL;
- src = old->src;
- }
-
- src_ch->table->pipe_busy = 1;
- rte_update2(dst, n->n.addr, e, src);
- src_ch->table->pipe_busy = 0;
+ rte_update(dst, n, NULL, old->src);
}
static int
-pipe_preexport(struct proto *P, rte *e)
+pipe_preexport(struct channel *c, rte *e)
{
- struct proto *pp = e->sender->proto;
+ struct pipe_proto *p = (void *) c->proto;
+
+ /* Avoid direct loopbacks */
+ if (e->sender == c->in_req.hook)
+ return -1;
+
+ /* Indirection check */
+ uint max_generation = ((struct pipe_config *) p->p.cf)->max_generation;
+ if (e->generation >= max_generation)
+ {
+ log_rl(&p->rl_gen, L_ERR "Route overpiped (%u hops of %u configured in %s) in table %s: %N %s/%u:%u",
+ e->generation, max_generation, c->proto->name,
+ c->table->name, e->net, e->src->proto->name, e->src->private_id, e->src->global_id);
- if (pp == P)
- return -1; /* Avoid local loops automatically */
+ return -1;
+ }
return 0;
}
@@ -187,6 +179,8 @@ pipe_init(struct proto_config *CF)
P->preexport = pipe_preexport;
P->reload_routes = pipe_reload_routes;
+ p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
+
pipe_configure_channels(p, cf);
return P;
@@ -218,8 +212,18 @@ pipe_get_status(struct proto *P, byte *buf)
static void
pipe_show_stats(struct pipe_proto *p)
{
- struct proto_stats *s1 = &p->pri->stats;
- struct proto_stats *s2 = &p->sec->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
@@ -243,24 +247,22 @@ pipe_show_stats(struct pipe_proto *p)
*/
cli_msg(-1006, " Routes: %u imported, %u exported",
- s1->imp_routes, s2->imp_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",
- s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
- s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_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",
- s2->exp_withdraws_received, s1->imp_withdraws_invalid,
- s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
+ rs2e->withdraws_received, s1i->withdraws_invalid,
+ rs1i->withdraws_ignored, rs1i->withdraws_accepted);
cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
- s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
- s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_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",
- s1->exp_withdraws_received, s2->imp_withdraws_invalid,
- s2->imp_withdraws_ignored, s2->imp_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)
{
@@ -269,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);
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index 038c6666..60c857eb 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -12,12 +12,14 @@
struct pipe_config {
struct proto_config c;
struct rtable_config *peer; /* Table we're connected to */
+ u8 max_generation;
};
struct pipe_proto {
struct proto p;
struct channel *pri;
struct channel *sec;
+ struct tbf rl_gen;
};
#endif
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 7985997a..24b1ce24 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -385,16 +385,16 @@ radv_trigger_valid(struct radv_config *cf)
}
static inline int
-radv_net_match_trigger(struct radv_config *cf, net *n)
+radv_net_match_trigger(struct radv_config *cf, const net_addr *n)
{
- return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
+ return radv_trigger_valid(cf) && net_equal(n, &cf->trigger);
}
int
-radv_preexport(struct proto *P, rte *new)
+radv_preexport(struct channel *c, rte *new)
{
// struct radv_proto *p = (struct radv_proto *) P;
- struct radv_config *cf = (struct radv_config *) (P->cf);
+ struct radv_config *cf = (struct radv_config *) (c->proto->cf);
if (radv_net_match_trigger(cf, new->net))
return RIC_PROCESS;
@@ -406,7 +406,7 @@ radv_preexport(struct proto *P, rte *new)
}
static void
-radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
+radv_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED)
{
struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (P->cf);
@@ -457,14 +457,14 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
(preference != RA_PREF_HIGH))
{
log(L_WARN "%s: Invalid ra_preference value %u on route %N",
- p->p.name, preference, n->n.addr);
+ p->p.name, preference, n);
preference = RA_PREF_MEDIUM;
preference_set = 1;
lifetime = 0;
lifetime_set = 1;
}
- rt = fib_get(&p->routes, n->n.addr);
+ rt = fib_get(&p->routes, n);
/* Ignore update if nothing changed */
if (rt->valid &&
@@ -487,7 +487,7 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
else
{
/* Withdraw */
- rt = fib_find(&p->routes, n->n.addr);
+ rt = fib_find(&p->routes, n);
if (!rt || !rt->valid)
return;
@@ -555,7 +555,7 @@ radv_check_active(struct radv_proto *p)
return 1;
struct channel *c = p->p.main_channel;
- return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
+ return rt_examine(c->table, &cf->trigger, c, c->out_filter);
}
static void
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index fa5b1289..e263172c 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -224,16 +224,15 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
a0.eattrs = &ea_block.l;
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a, p->p.main_source);
+ rte e0 = {
+ .attrs = &a0,
+ .src = p->p.main_source,
+ };
- rte_update(&p->p, en->n.addr, e);
+ rte_update(p->p.main_channel, en->n.addr, &e0, p->p.main_source);
}
else
- {
- /* Withdraw */
- rte_update(&p->p, en->n.addr, NULL);
- }
+ rte_update(p->p.main_channel, en->n.addr, NULL, p->p.main_source);
}
/**
@@ -328,8 +327,8 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
* it into our data structures.
*/
static void
-rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
- struct rte *old UNUSED)
+rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, struct rte *new,
+ const struct rte *old UNUSED)
{
struct rip_proto *p = (struct rip_proto *) P;
struct rip_entry *en;
@@ -346,14 +345,14 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
if (rt_metric > p->infinity)
{
log(L_WARN "%s: Invalid rip_metric value %u for route %N",
- p->p.name, rt_metric, net->n.addr);
+ p->p.name, rt_metric, net);
rt_metric = p->infinity;
}
if (rt_tag > 0xffff)
{
log(L_WARN "%s: Invalid rip_tag value %u for route %N",
- p->p.name, rt_tag, net->n.addr);
+ p->p.name, rt_tag, net);
rt_metric = p->infinity;
rt_tag = 0;
}
@@ -365,7 +364,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
* collection.
*/
- en = fib_get(&p->rtable, net->n.addr);
+ en = fib_get(&p->rtable, net);
old_metric = en->valid ? en->metric : -1;
@@ -379,7 +378,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
else
{
/* Withdraw */
- en = fib_find(&p->rtable, net->n.addr);
+ en = fib_find(&p->rtable, net);
if (!en || en->valid != RIP_ENTRY_VALID)
return;
diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c
index d246dd50..4a52b54b 100644
--- a/proto/rpki/packets.c
+++ b/proto/rpki/packets.c
@@ -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);
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index 6e111a81..f1d32628 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -127,19 +127,16 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
.dest = RTD_NONE,
};
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a, p->p.main_source);
+ rte e0 = { .attrs = &a0, .src = p->p.main_source, };
- e->pflags = 0;
-
- rte_update2(channel, &pfxr->n, e, e->src);
+ rte_update(channel, &pfxr->n, &e0, p->p.main_source);
}
void
rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr)
{
struct rpki_proto *p = cache->p;
- rte_update2(channel, &pfxr->n, NULL, p->p.main_source);
+ rte_update(channel, &pfxr->n, NULL, p->p.main_source);
}
@@ -387,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)
@@ -433,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)
@@ -478,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;
@@ -828,16 +834,27 @@ rpki_show_proto_info(struct proto *P)
if (cache)
{
const char *transport_name = "---";
+ uint default_port = 0;
switch (cf->tr_config.type)
{
#if HAVE_LIBSSH
- case RPKI_TR_SSH: transport_name = "SSHv2"; break;
+ case RPKI_TR_SSH:
+ transport_name = "SSHv2";
+ default_port = RPKI_SSH_PORT;
+ break;
#endif
- case RPKI_TR_TCP: transport_name = "Unprotected over TCP"; break;
+ case RPKI_TR_TCP:
+ transport_name = "Unprotected over TCP";
+ default_port = RPKI_TCP_PORT;
+ break;
};
cli_msg(-1006, " Cache server: %s", cf->hostname);
+
+ if (cf->port != default_port)
+ cli_msg(-1006, " Cache port: %u", cf->port);
+
cli_msg(-1006, " Status: %s", rpki_cache_state_to_str(cache->state));
cli_msg(-1006, " Transport: %s", transport_name);
cli_msg(-1006, " Protocol version: %u", cache->version);
diff --git a/proto/rpki/transport.c b/proto/rpki/transport.c
index a1ac7587..81bd6dd8 100644
--- a/proto/rpki/transport.c
+++ b/proto/rpki/transport.c
@@ -85,6 +85,7 @@ rpki_tr_open(struct rpki_tr_sock *tr)
sk->rbsize = RPKI_RX_BUFFER_SIZE;
sk->tbsize = RPKI_TX_BUFFER_SIZE;
sk->tos = IP_PREC_INTERNET_CONTROL;
+ sk->vrf = cache->p->p.vrf;
if (ipa_zero(sk->daddr) && sk->host)
{
diff --git a/proto/static/static.c b/proto/static/static.c
index 3a0d9257..fe0c77bc 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -103,24 +103,13 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
return;
/* We skip rta_lookup() here */
- rte *e = rte_get_temp(a, src);
- e->pflags = 0;
+ rte e0 = { .attrs = a, .src = src, .net = r->net, }, *e = &e0;
+ /* Evaluate the filter */
if (r->cmds)
- {
- /* Create a temporary table node */
- e->net = alloca(sizeof(net) + r->net->length);
- memset(e->net, 0, sizeof(net) + r->net->length);
- net_copy(e->net->n.addr, r->net);
-
- /* Evaluate the filter */
- f_eval_rte(r->cmds, &e, static_lp);
-
- /* Remove the temporary node */
- e->net = NULL;
- }
+ f_eval_rte(r->cmds, e, static_lp);
- rte_update2(p->p.main_channel, r->net, e, src);
+ rte_update(p->p.main_channel, r->net, e, src);
r->state = SRS_CLEAN;
if (r->cmds)
@@ -132,7 +121,7 @@ withdraw:
if (r->state == SRS_DOWN)
return;
- rte_update2(p->p.main_channel, r->net, NULL, src);
+ rte_update(p->p.main_channel, r->net, NULL, src);
r->state = SRS_DOWN;
}
@@ -298,7 +287,7 @@ static void
static_remove_rte(struct static_proto *p, struct static_route *r)
{
if (r->state)
- rte_update2(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
+ rte_update(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
static_reset_rte(p, r);
}
@@ -518,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
@@ -788,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,