From: Maria Matejka Date: Sun, 30 May 2021 11:07:16 +0000 (+0200) Subject: Babel: Seqno requests are properly decoupled from neighbors when the underlying inter... X-Git-Tag: v2.0.9~55 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ebd5751cdeb4c753c6c9df31b82dcd6afee2cd39;p=thirdparty%2Fbird.git Babel: Seqno requests are properly decoupled from neighbors when the underlying interface disappears When an interface disappears, all the neighbors are freed as well. Seqno requests were anyway not decoupled from them, leading to strange segfaults. This fix adds a proper seqno request list inside neighbors to make sure that no pointer to neighbor is kept after free. --- diff --git a/lib/lists.h b/lib/lists.h index 066eafbb0..479f4ed1a 100644 --- a/lib/lists.h +++ b/lib/lists.h @@ -59,6 +59,8 @@ typedef union list { /* In fact two overlayed nodes */ /* WALK_LIST_FIRST supposes that called code removes each processed node */ #define WALK_LIST_FIRST(n,list) \ while(n=HEAD(list), (NODE (n))->next) +#define WALK_LIST_FIRST2(n,pos,list) \ + while(n=SKIP_BACK(typeof(*n),pos,HEAD(list)), (n)->pos.next) #define WALK_LIST_BACKWARDS(n,list) for(n=TAIL(list);(NODE (n))->prev; \ n=(void *)((NODE (n))->prev)) #define WALK_LIST_BACKWARDS_DELSAFE(n,prv,list) \ diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 25d8e3304..fdebc3526 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -56,13 +56,6 @@ static void babel_update_cost(struct babel_neighbor *n); static inline void babel_kick_timer(struct babel_proto *p); static inline void babel_iface_kick_timer(struct babel_iface *ifa); -static inline void babel_lock_neighbor(struct babel_neighbor *nbr) -{ if (nbr) nbr->uc++; } - -static inline void babel_unlock_neighbor(struct babel_neighbor *nbr) -{ if (nbr && !--nbr->uc) mb_free(nbr); } - - /* * Functions to maintain data structures */ @@ -316,8 +309,9 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e, return; /* Found older */ - babel_unlock_neighbor(sr->nbr); rem_node(NODE sr); + rem_node(&sr->nbr_node); + goto found; } @@ -330,7 +324,10 @@ found: sr->hop_count = hop_count; sr->count = 0; sr->expires = current_time() + BABEL_SEQNO_REQUEST_EXPIRY; - babel_lock_neighbor(sr->nbr = nbr); + + if (sr->nbr = nbr) + add_tail(&nbr->requests, &sr->nbr_node); + add_tail(&e->requests, NODE sr); babel_send_seqno_request(p, e, sr); @@ -339,7 +336,9 @@ found: static void babel_remove_seqno_request(struct babel_proto *p, struct babel_seqno_request *sr) { - babel_unlock_neighbor(sr->nbr); + if (sr->nbr) + rem_node(&sr->nbr_node); + rem_node(NODE sr); sl_free(p->seqno_slab, sr); } @@ -427,7 +426,7 @@ babel_get_neighbor(struct babel_iface *ifa, ip_addr addr) nbr->txcost = BABEL_INFINITY; nbr->cost = BABEL_INFINITY; init_list(&nbr->routes); - babel_lock_neighbor(nbr); + init_list(&nbr->requests); add_tail(&ifa->neigh_list, NODE nbr); return nbr; @@ -448,9 +447,16 @@ babel_flush_neighbor(struct babel_proto *p, struct babel_neighbor *nbr) babel_flush_route(p, r); } + struct babel_seqno_request *sr; + WALK_LIST_FIRST2(sr, nbr_node, nbr->requests) + { + sr->nbr = NULL; + rem_node(&sr->nbr_node); + } + nbr->ifa = NULL; rem_node(NODE nbr); - babel_unlock_neighbor(nbr); + mb_free(nbr); } static void diff --git a/proto/babel/babel.h b/proto/babel/babel.h index e075024cb..09bf530c2 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -198,7 +198,6 @@ struct babel_neighbor { struct babel_iface *ifa; ip_addr addr; - uint uc; /* Reference counter for seqno requests */ u16 rxcost; /* Sent in last IHU */ u16 txcost; /* Received in last IHU */ u16 cost; /* Computed neighbor cost */ @@ -212,6 +211,7 @@ struct babel_neighbor { btime ihu_expiry; list routes; /* Routes this neighbour has sent us (struct babel_route) */ + list requests; /* Seqno requests bound to this neighbor */ }; struct babel_source { @@ -241,6 +241,7 @@ struct babel_route { struct babel_seqno_request { node n; + node nbr_node; u64 router_id; u16 seqno; u8 hop_count;