From c83876265eeae3591bfe90375503728e633cb807 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 11 Feb 2010 22:27:06 +0100 Subject: [PATCH] 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. --- nest/proto.c | 11 +++++++++++ nest/protocol.h | 14 ++++++++++++++ nest/rt-table.c | 2 +- proto/pipe/pipe.c | 21 ++++++++++----------- 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, };