summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-02-11 22:27:06 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2010-02-11 22:27:06 +0100
commitc83876265eeae3591bfe90375503728e633cb807 (patch)
treeee5302b85bf3d9dc1da67a9d59ca9eb4bbfd83f9
parenta2ea1bac601ca79946e2a215dac9427c526cedab (diff)
Fixes a tricky bug in the pipe protocol.
When uncofiguring the pipe and the peer table, the peer table was unlocked when pipe protocol state changed to down/flushing and not to down/hungry. This leads to the removal of the peer table before the routes from the pipe were flushed. The fix leads to adding some pipe-specific hacks to the nest, but this seems inevitable.
-rw-r--r--nest/proto.c11
-rw-r--r--nest/protocol.h14
-rw-r--r--nest/rt-table.c2
-rw-r--r--proto/pipe/pipe.c21
4 files changed, 36 insertions, 12 deletions
diff --git a/nest/proto.c b/nest/proto.c
index 870edddd..c6b7e63c 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -133,6 +133,11 @@ 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
}
/**
@@ -583,6 +588,12 @@ proto_fell_down(struct proto *p)
bzero(&p->stats, sizeof(struct proto_stats));
rt_unlock_table(p->table);
+
+#ifdef CONFIG_PIPE
+ if (proto_is_pipe(p))
+ rt_unlock_table(pipe_get_peer_table(p));
+#endif
+
proto_rethink_goal(p);
}
diff --git a/nest/protocol.h b/nest/protocol.h
index 5a69b33b..99d8dc80 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -334,4 +334,18 @@ struct announce_hook {
struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *);
+/*
+ * Some pipe-specific nest hacks
+ */
+
+#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);
+
+#endif
+
+
#endif
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 413675c9..fee57189 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -642,7 +642,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
/* Do not filter routes going through the pipe,
they are filtered in the export filter only. */
#ifdef CONFIG_PIPE
- if (p->proto == &proto_pipe)
+ if (proto_is_pipe(p))
filter = FILTER_ACCEPT;
#endif
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index aa76a152..d9df03ba 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -138,6 +138,9 @@ pipe_start(struct proto *P)
* 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));
@@ -170,20 +173,10 @@ pipe_start(struct proto *P)
*/
a = proto_add_announce_hook(P, p->peer);
a->proto = &ph->p;
- rt_lock_table(p->peer);
return PS_UP;
}
-static int
-pipe_shutdown(struct proto *P)
-{
- struct pipe_proto *p = (struct pipe_proto *) P;
-
- rt_unlock_table(p->peer);
- return PS_DOWN;
-}
-
static struct proto *
pipe_init(struct proto_config *C)
{
@@ -234,13 +227,19 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
return 1;
}
+struct rtable *
+pipe_get_peer_table(struct proto *P)
+{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+ return p->peer;
+}
+
struct protocol proto_pipe = {
name: "Pipe",
template: "pipe%d",
postconfig: pipe_postconfig,
init: pipe_init,
start: pipe_start,
- shutdown: pipe_shutdown,
reconfigure: pipe_reconfigure,
get_status: pipe_get_status,
};