Commit dca75fd7 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Removes phantom protocol from the pipe design.

It seems that by adding one pipe-specific exception to route
announcement code and by adding one argument to rt_notify() callback i
could completely eliminate the need for the phantom protocol instance
and therefore make the code more straightforward. It will also fix some
minor bugs (like ignoring debug flag changes from the command line).
parent 9db74169
......@@ -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.
......
......@@ -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
}
/**
......
......@@ -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
......
......@@ -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)
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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",
......
......@@ -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
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment