break;
case IFNOT_NEIGHBOR:
if (!s->neigh_notify) return;
- neigh_link(x.n);
+ neigh_link_locked(x.n);
break;
default:
bug("Unknown interface notification type: %d", x.type);
break;
case IFNOT_NEIGHBOR:
s->neigh_notify(n->n);
- IFACE_LOCK;
neigh_unlink(n->n);
- IFACE_UNLOCK;
break;
default:
bug("Bad interface notification type: %d", n->type);
IFACE_LOCK;
SKIP_BACK_DECLARE(struct proto, p, iface_sub, s);
- WALK_TLIST_DELSAFE(proto_neigh, n, &p->neighbors)
- neigh_unlink(n);
ifsub_rem_node(&iface_sub_list, s);
ev_postpone(&s->event);
if_unlink(n->i);
break;
case IFNOT_NEIGHBOR:
- neigh_unlink(n->n);
+ neigh_unlink_locked(n->n);
break;
default:
bug("Bad interface notification type: %d", n->type);
sl_free(n);
}
+ WALK_TLIST_DELSAFE(proto_neigh, n, &p->neighbors)
+ {
+ log(L_WARN "%s: Unlinking forgotten neighbor %I", p->name, n->addr);
+ neigh_unlink_locked(n);
+ }
+
ASSERT_DIE(EMPTY_TLIST(proto_neigh, &p->neighbors));
IFACE_UNLOCK;
#define _BIRD_IFACE_H_
#include "lib/locking.h"
+#include "lib/defer.h"
#include "lib/event.h"
#include "lib/lists.h"
#include "lib/tlists.h"
void neigh_link(neighbor *);
void neigh_unlink(neighbor *);
+struct neigh_unlink_deferred {
+ struct deferred_call dc;
+ neighbor *n;
+};
+
+void neigh_unlink_deferred(struct deferred_call *dc);
+
+static inline void neigh_unlink_later(neighbor *n)
+{
+ struct neigh_unlink_deferred nud = {
+ .dc.hook = neigh_unlink_deferred,
+ .n = n,
+ };
+
+ defer_call(&nud.dc, sizeof nud);
+}
+
+/* For internal use */
+void neigh_link_locked(neighbor *);
+void neigh_unlink_locked(neighbor *);
+
/*
* Notification mechanism
*/
n->flags = flags;
n->scope = scope;
- neigh_link(n);
+ neigh_link_locked(n);
+ neigh_unlink_later(n);
IFACE_UNLOCK;
return n;
}
void
-neigh_link(neighbor *n)
+neigh_link_locked(neighbor *n)
{
IFACE_ASSERT_LOCKED;
n->uc++;
}
void
-neigh_unlink(neighbor *n)
+neigh_unlink_locked(neighbor *n)
{
IFACE_ASSERT_LOCKED;
if (--n->uc)
sl_free(n);
}
+void
+neigh_link(neighbor *n)
+{
+ IFACE_LOCK;
+ neigh_link_locked(n);
+ IFACE_UNLOCK;
+}
+
+void
+neigh_unlink(neighbor *n)
+{
+ IFACE_LOCK;
+ neigh_unlink_locked(n);
+ IFACE_UNLOCK;
+}
+
+void neigh_unlink_deferred(struct deferred_call *dc)
+{
+ neigh_unlink(SKIP_BACK(struct neigh_unlink_deferred, dc, dc)->n);
+}
+
/**
* neigh_update: update neighbor entry w.r.t. change on specific iface
* @n: neighbor to update
if ((n->scope < 0) && !(n->flags & NEF_STICKY))
{
- neigh_unlink(n);
+ neigh_unlink_locked(n);
return;
}
if (p->do_stop)
{
- iface_unsubscribe(&p->iface_sub);
-
p->do_stop = 0;
}
if (proto_is_done(p) && p->pool_inloop) /* perusing pool_inloop to do this once only */
{
+ /* Interface notification unsubscribe can't be done
+ * before the protocol is really done, as it also destroys
+ * the neighbors which may be needed (e.g. by BGP->MRT)
+ * during the STOP phase as well. */
+ iface_unsubscribe(&p->iface_sub);
+
rp_free(p->pool_inloop);
p->pool_inloop = NULL;
if (p->loop != &main_birdloop)
return;
}
+ neigh_link(nb);
+
n->neigh = nb;
nb->data = n;
bfd_stop_neighbor(struct bfd_proto *p UNUSED, struct bfd_neighbor *n)
{
if (n->neigh)
+ {
n->neigh->data = NULL;
- n->neigh = NULL;
+ neigh_unlink(n->neigh);
+ n->neigh = NULL;
+ }
rfree(n->req);
n->req = NULL;
bgp_close(p);
}
- p->neigh = NULL;
+ if (p->neigh)
+ {
+ neigh_unlink(p->neigh);
+ p->neigh = NULL;
+ }
BGP_TRACE(D_EVENTS, "Down");
proto_notify_state(&p->p, PS_DOWN);
}
p->neigh = n;
+ neigh_link(n);
if (n->scope <= 0)
BGP_TRACE(D_EVENTS, "Waiting for %I%J to become my neighbor", p->remote_ip, cf->iface);
struct rip_neighbor *n = mb_allocz(p->p.pool, sizeof(struct rip_neighbor));
n->ifa = ifa;
n->nbr = nbr;
+ neigh_link(nbr);
+
nbr->data = n;
n->csn = nbr->aux;
nbr->data = NULL;
nbr->aux = n->csn;
+ neigh_unlink(nbr);
+
rfree(n->bfd_req);
n->bfd_req = NULL;
n->last_seen = 0;
continue;
}
+ neigh_link(n);
+
r2->neigh = n;
r2->chain = n->data;
n->data = r2;
for (r2 = r; r2; r2 = r2->mp_next)
{
- r2->neigh = NULL;
+ if (r2->neigh)
+ {
+ r2->neigh->data = NULL;
+ neigh_unlink(r2->neigh);
+ r2->neigh = NULL;
+ }
+
r2->chain = NULL;
r2->state = 0;