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.
This commit is contained in:
parent
a2ea1bac60
commit
c83876265e
4 changed files with 36 additions and 12 deletions
11
nest/proto.c
11
nest/proto.c
|
@ -133,6 +133,11 @@ proto_init_instance(struct proto *p)
|
||||||
p->attn = ev_new(p->pool);
|
p->attn = ev_new(p->pool);
|
||||||
p->attn->data = p;
|
p->attn->data = p;
|
||||||
rt_lock_table(p->table);
|
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));
|
bzero(&p->stats, sizeof(struct proto_stats));
|
||||||
rt_unlock_table(p->table);
|
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);
|
proto_rethink_goal(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -334,4 +334,18 @@ struct announce_hook {
|
||||||
|
|
||||||
struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *);
|
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
|
#endif
|
||||||
|
|
|
@ -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,
|
/* Do not filter routes going through the pipe,
|
||||||
they are filtered in the export filter only. */
|
they are filtered in the export filter only. */
|
||||||
#ifdef CONFIG_PIPE
|
#ifdef CONFIG_PIPE
|
||||||
if (p->proto == &proto_pipe)
|
if (proto_is_pipe(p))
|
||||||
filter = FILTER_ACCEPT;
|
filter = FILTER_ACCEPT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,9 @@ pipe_start(struct proto *P)
|
||||||
* end of the pipe (we need to do this in order to get different
|
* end of the pipe (we need to do this in order to get different
|
||||||
* filters and announce functions and it unfortunately involves
|
* filters and announce functions and it unfortunately involves
|
||||||
* a couple of magic trickery).
|
* 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));
|
ph = mb_alloc(P->pool, sizeof(struct pipe_proto));
|
||||||
memcpy(ph, p, 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_add_announce_hook(P, p->peer);
|
||||||
a->proto = &ph->p;
|
a->proto = &ph->p;
|
||||||
rt_lock_table(p->peer);
|
|
||||||
|
|
||||||
return PS_UP;
|
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 *
|
static struct proto *
|
||||||
pipe_init(struct proto_config *C)
|
pipe_init(struct proto_config *C)
|
||||||
{
|
{
|
||||||
|
@ -234,13 +227,19 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
|
||||||
return 1;
|
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 = {
|
struct protocol proto_pipe = {
|
||||||
name: "Pipe",
|
name: "Pipe",
|
||||||
template: "pipe%d",
|
template: "pipe%d",
|
||||||
postconfig: pipe_postconfig,
|
postconfig: pipe_postconfig,
|
||||||
init: pipe_init,
|
init: pipe_init,
|
||||||
start: pipe_start,
|
start: pipe_start,
|
||||||
shutdown: pipe_shutdown,
|
|
||||||
reconfigure: pipe_reconfigure,
|
reconfigure: pipe_reconfigure,
|
||||||
get_status: pipe_get_status,
|
get_status: pipe_get_status,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue