summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nest/proto-hooks.c3
-rw-r--r--nest/proto.c5
-rw-r--r--nest/protocol.h11
-rw-r--r--nest/rt-table.c24
-rw-r--r--proto/bgp/attrs.c2
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/ospf/ospf.c5
-rw-r--r--proto/pipe/pipe.c86
-rw-r--r--proto/pipe/pipe.h14
-rw-r--r--proto/rip/rip.c3
-rw-r--r--sysdep/unix/krt.c3
11 files changed, 55 insertions, 103 deletions
diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c
index c30b107..3d19e3f 100644
--- a/nest/proto-hooks.c
+++ b/nest/proto-hooks.c
@@ -178,13 +178,14 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
/**
* rt_notify - notify instance about routing table change
* @p: protocol instance
+ * @table: a routing table
* @net: a network entry
* @new: new route for the network
* @old: old route for the network
* @attrs: extended attributes associated with the @new entry
*
* The rt_notify() hook is called to inform the protocol instance about
- * changes in the routing table it's connected to, that is a route @old
+ * changes in the connected routing table @table, that is a route @old
* belonging to network @net being replaced by a new route @new with
* extended attributes @attrs. Either @new or @old or both can be %NULL
* if the corresponding route doesn't exist.
diff --git a/nest/proto.c b/nest/proto.c
index a7e4e0c..57c2aa1 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -133,11 +133,6 @@ proto_init_instance(struct proto *p)
p->attn = ev_new(p->pool);
p->attn->data = p;
rt_lock_table(p->table);
-
-#ifdef CONFIG_PIPE
- if (proto_is_pipe(p))
- rt_lock_table(pipe_get_peer_table(p));
-#endif
}
/**
diff --git a/nest/protocol.h b/nest/protocol.h
index 876427a..82f3766 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -16,6 +16,7 @@
struct iface;
struct ifa;
+struct rtable;
struct rte;
struct neighbor;
struct rta;
@@ -162,7 +163,7 @@ struct proto {
void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
- void (*rt_notify)(struct proto *, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs);
+ void (*rt_notify)(struct proto *, struct rtable *table, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs);
void (*neigh_notify)(struct neighbor *neigh);
struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs);
@@ -339,13 +340,7 @@ struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *);
*/
#ifdef CONFIG_PIPE
-
-static inline int proto_is_pipe(struct proto *p)
-{ return p->proto == &proto_pipe; }
-
-struct rtable *pipe_get_peer_table(struct proto *p);
-struct proto_stats *pipe_get_peer_stats(struct proto *p);
-
+#include "proto/pipe/pipe.h"
#endif
diff --git a/nest/rt-table.c b/nest/rt-table.c
index c9e421e..72a1cb0 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -161,6 +161,7 @@ static inline void
do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed)
{
struct proto *p = a->proto;
+ struct filter *filter = p->out_filter;
struct proto_stats *stats = &p->stats;
rte *new0 = new;
rte *old0 = old;
@@ -168,6 +169,15 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
int fast_exit_hack = 0;
+#ifdef CONFIG_PIPE
+ /* The secondary direction of the pipe */
+ if (proto_is_pipe(p) && (p->table != a->table))
+ {
+ filter = p->in_filter;
+ stats = pipe_get_peer_stats(p);
+ }
+#endif
+
if (new)
{
stats->exp_updates_received++;
@@ -186,8 +196,8 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
}
else if (ok)
rte_trace_out(D_FILTERS, p, new, "forced accept by protocol");
- else if (p->out_filter == FILTER_REJECT ||
- p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
+ else if (filter == FILTER_REJECT ||
+ filter && f_run(filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
{
stats->exp_updates_filtered++;
drop_reason = "filtered out";
@@ -230,13 +240,13 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
if (old && !refeed)
{
- if (p->out_filter == FILTER_REJECT)
+ if (filter == FILTER_REJECT)
old = NULL;
else
{
ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL;
ok = p->import_control ? p->import_control(p, &old, &tmpb, rte_update_pool) : 0;
- if (ok < 0 || (!ok && p->out_filter && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
+ if (ok < 0 || (!ok && filter && f_run(filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
{
if (old != old0)
rte_free(old);
@@ -271,18 +281,18 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
rte_trace_out(D_ROUTES, p, old, "removed");
}
if (!new)
- p->rt_notify(p, net, NULL, old, NULL);
+ p->rt_notify(p, a->table, net, NULL, old, NULL);
else if (tmpa)
{
ea_list *t = tmpa;
while (t->next)
t = t->next;
t->next = new->attrs->eattrs;
- p->rt_notify(p, net, new, old, tmpa);
+ p->rt_notify(p, a->table, net, new, old, tmpa);
t->next = NULL;
}
else
- p->rt_notify(p, net, new, old, new->attrs->eattrs);
+ p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs);
if (new && new != new0) /* Discard temporary rte's */
rte_free(new);
if (old && old != old0)
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 4cfabf1..9667987 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -772,7 +772,7 @@ bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
}
void
-bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
+bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
{
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_bucket *buck;
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 7f574ed..1a29195 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -179,7 +179,7 @@ byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned att
struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory);
int bgp_get_attr(struct eattr *e, byte *buf, int buflen);
int bgp_rte_better(struct rte *, struct rte *);
-void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *);
+void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
void bgp_attr_init(struct bgp_proto *);
unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index d2ceab2..26a05d9 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -78,7 +78,7 @@
static int ospf_reload_routes(struct proto *p);
-static void ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
+static void ospf_rt_notify(struct proto *p, struct rtable *table UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
static int ospf_rte_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old);
@@ -484,8 +484,7 @@ ospf_shutdown(struct proto *p)
}
static void
-ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
- ea_list * attrs)
+ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs)
{
struct proto_ospf *po = (struct proto_ospf *) p;
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 879135d..943d3a0 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -31,9 +31,12 @@
#include "pipe.h"
static void
-pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs)
+pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+ rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */
struct proto *src;
+
net *nn;
rte *e;
rta a;
@@ -85,30 +88,12 @@ pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *ne
src_table->pipe_busy = 0;
}
-static void
-pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
-
- DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
- pipe_send(p, p->p.table, p->peer, net, new, old, attrs);
-}
-
-static void
-pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs)
-{
- struct pipe_proto *p = ((struct pipe_proto *) P)->phantom;
-
- DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen);
- pipe_send(p, p->peer, p->p.table, net, new, old, attrs);
-}
-
static int
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
{
struct proto *pp = (*ee)->sender;
- if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p)
+ if (pp == P)
return -1; /* Avoid local loops automatically */
return 0;
}
@@ -130,49 +115,16 @@ static int
pipe_start(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
- struct pipe_proto *ph;
struct announce_hook *a;
- /*
- * Create a phantom protocol which will represent the remote
- * end of the pipe (we need to do this in order to get different
- * filters and announce functions and it unfortunately involves
- * a couple of magic trickery).
- *
- * The phantom protocol is used ONLY in announce hooks and
- * therefore in do_rte_announce() function.
- */
- ph = mb_alloc(P->pool, sizeof(struct pipe_proto));
- memcpy(ph, p, sizeof(struct pipe_proto));
- p->phantom = ph;
- ph->phantom = p;
- ph->p.accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY;
- ph->p.rt_notify = pipe_rt_notify_sec;
- ph->p.proto_state = PS_UP;
- ph->p.core_state = ph->p.core_goal = FS_HAPPY;
+ /* Clean up the secondary stats */
+ bzero(&p->peer_stats, sizeof(struct proto_stats));
- /*
- * Routes should be filtered in the do_rte_announce() (export
- * filter for protocols). Reverse direction is handled by putting
- * specified import filter to out_filter field of the phantom
- * protocol.
- *
- * in_filter fields are not important, there is an exception in
- * rte_update() to ignore it for pipes. We cannot just set
- * P->in_filter to FILTER_ACCEPT, because that would break other
- * things (reconfiguration, show-protocols command).
- */
- ph->p.in_filter = FILTER_ACCEPT;
- ph->p.out_filter = P->in_filter;
+ /* Lock the peer table, unlock is handled in proto_fell_down() */
+ rt_lock_table(p->peer);
- /*
- * Connect the phantom protocol to the peer routing table, but
- * keep it in the list of connections of the primary protocol,
- * so that it gets disconnected at the right time and we also
- * get all routes from both sides during the feeding phase.
- */
+ /* Connect the protocol also to the peer routing table. */
a = proto_add_announce_hook(P, p->peer);
- a->proto = &ph->p;
return PS_UP;
}
@@ -187,9 +139,10 @@ pipe_init(struct proto_config *C)
p->peer = c->peer->table;
p->mode = c->mode;
P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY;
- P->rt_notify = pipe_rt_notify_pri;
+ P->rt_notify = pipe_rt_notify;
P->import_control = pipe_import_control;
P->reload_routes = pipe_reload_routes;
+
return P;
}
@@ -222,24 +175,9 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
if ((o->peer->table != n->peer->table) || (o->mode != n->mode))
return 0;
- /* Update also the filter in the phantom protocol */
- p->phantom->p.out_filter = new->in_filter;
return 1;
}
-struct rtable *
-pipe_get_peer_table(struct proto *P)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
- return p->peer;
-}
-
-struct proto_stats *
-pipe_get_peer_stats(struct proto *P)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
- return &p->phantom->p.stats;
-}
struct protocol proto_pipe = {
name: "Pipe",
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index 368ba41..fbd2129 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -21,8 +21,20 @@ struct pipe_config {
struct pipe_proto {
struct proto p;
struct rtable *peer;
+ struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
- struct pipe_proto *phantom;
};
+
+extern struct protocol proto_pipe;
+
+static inline int proto_is_pipe(struct proto *p)
+{ return p->proto == &proto_pipe; }
+
+static inline struct rtable * pipe_get_peer_table(struct proto *P)
+{ return ((struct pipe_proto *) P)->peer; }
+
+static inline struct proto_stats * pipe_get_peer_stats(struct proto *P)
+{ return &((struct pipe_proto *) P)->peer_stats; }
+
#endif
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index f9a160e..d69d643 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -864,7 +864,8 @@ rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
* own), so store it into our data structures.
*/
static void
-rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs)
+rip_rt_notify(struct proto *p, struct rtable *table UNUSED, struct network *net,
+ struct rte *new, struct rte *old, struct ea_list *attrs)
{
CHK_MAGIC;
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 488447b..6d94cad 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -742,7 +742,8 @@ krt_scan(timer *t UNUSED)
*/
static void
-krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED)
+krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
+ rte *new, rte *old, struct ea_list *attrs UNUSED)
{
struct krt_proto *p = (struct krt_proto *) P;