]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Interface subsystem locking
authorMaria Matejka <mq@ucw.cz>
Tue, 4 Apr 2023 14:41:55 +0000 (16:41 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 4 Apr 2023 15:00:58 +0000 (17:00 +0200)
nest/iface.c
nest/iface.h
nest/neighbor.c
nest/proto.c
proto/babel/babel.c
proto/ospf/iface.c
proto/radv/radv.c
proto/rip/rip.c
sysdep/bsd/krt-sock.c
sysdep/linux/netlink.c

index c49ad95e6abfe6f0de4fb4fb56e0d3c69ffd7349..f1938664f8cc2102ce00ba244475e0a5d5c30948 100644 (file)
 #include "nest/cli.h"
 #include "lib/resource.h"
 #include "lib/string.h"
+#include "lib/locking.h"
 #include "conf/conf.h"
 #include "sysdep/unix/krt.h"
 
+DOMAIN(attrs) iface_domain;
+
+#define IFACE_LOCK     LOCK_DOMAIN(attrs, iface_domain)
+#define IFACE_UNLOCK   UNLOCK_DOMAIN(attrs, iface_domain)
+#define IFACE_ASSERT_LOCKED    ASSERT_DIE(DOMAIN_IS_LOCKED(attrs, iface_domain))
 
 static TLIST_LIST(ifsub) iface_sub_list;
 static slab *iface_sub_slab;
 static pool *if_pool;
 
-list iface_list;
+list global_iface_list;
 struct iface default_vrf;
 
 static void if_recalc_preferred(struct iface *i);
 
+static void ifa_dump_locked(struct ifa *);
+static void if_dump_locked(struct iface *);
+
+struct iface *
+if_walk_first(void)
+{
+  IFACE_LOCK;
+  struct iface *i = HEAD(global_iface_list);
+  return NODE_VALID(i) ? i : NULL;
+}
+
+struct iface *
+if_walk_next(struct iface *i)
+{
+  IFACE_ASSERT_LOCKED;
+  i = NODE_NEXT(i);
+  return NODE_VALID(i) ? i : NULL;
+}
+
+void
+if_walk_done(void)
+{
+  IFACE_ASSERT_LOCKED;
+  IFACE_UNLOCK;
+}
+
 /**
  * ifa_dump - dump interface address
  * @a: interface address descriptor
@@ -52,6 +84,14 @@ static void if_recalc_preferred(struct iface *i);
  */
 void
 ifa_dump(struct ifa *a)
+{
+  IFACE_LOCK;
+  ifa_dump_locked(a);
+  IFACE_UNLOCK;
+}
+
+static void
+ifa_dump_locked(struct ifa *a)
 {
   debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
        (a->flags & IA_PRIMARY) ? " PRIMARY" : "",
@@ -69,6 +109,14 @@ ifa_dump(struct ifa *a)
  */
 void
 if_dump(struct iface *i)
+{
+  IFACE_LOCK;
+  if_dump_locked(i);
+  IFACE_UNLOCK;
+}
+
+static void
+if_dump_locked(struct iface *i)
 {
   struct ifa *a;
 
@@ -96,7 +144,7 @@ if_dump(struct iface *i)
   debug(" MTU=%d\n", i->mtu);
   WALK_LIST(a, i->addrs)
     {
-      ifa_dump(a);
+      ifa_dump_locked(a);
       ASSERT(!!(a->flags & IA_PRIMARY) ==
             ((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
     }
@@ -111,14 +159,60 @@ if_dump(struct iface *i)
 void
 if_dump_all(void)
 {
-  struct iface *i;
-
   debug("Known network interfaces:\n");
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     if_dump(i);
   debug("Router ID: %08x\n", config->router_id);
 }
 
+void
+if_link(struct iface *i)
+{
+  IFACE_ASSERT_LOCKED;
+
+  if (i)
+    i->uc++;
+}
+
+void
+if_unlink(struct iface *i)
+{
+  IFACE_ASSERT_LOCKED;
+
+  if (i)
+    i->uc--;
+  /* TODO: Do some interface object cleanup */
+}
+
+void ifa_link(struct ifa *a)
+{
+  IFACE_ASSERT_LOCKED;
+
+  if (a)
+  {
+    debug("ifa_link: %p %d\n", a, a->uc);
+    a->uc++;
+  }
+}
+
+void ifa_unlink(struct ifa *a)
+{
+  IFACE_ASSERT_LOCKED;
+
+  if (!a)
+    return;
+
+  debug("ifa_unlink: %p %d\n", a, a->uc);
+  if (--a->uc)
+    return;
+
+  if_unlink(a->iface);
+#if DEBUGGING
+  memset(a, 0x5b, sizeof(struct ifa));
+#endif
+  mb_free(a);
+}
+
 static inline unsigned
 if_what_changed(struct iface *i, struct iface *j)
 {
@@ -151,6 +245,8 @@ if_copy(struct iface *to, struct iface *from)
 void
 if_enqueue_notify_to(struct iface_notification x, struct iface_subscription *s)
 {
+  IFACE_ASSERT_LOCKED;
+
   switch (x.type) {
     case IFNOT_ADDRESS:
       if (!s->ifa_notify) return;
@@ -174,12 +270,14 @@ if_enqueue_notify_to(struct iface_notification x, struct iface_subscription *s)
   debug("Enqueue notify %d/%p (%p) to %p\n", x.type, x.a, in, s);
 
   ifnot_add_tail(&s->queue, in);
-  ev_schedule(&s->event);
+  ev_send(s->target, &s->event);
 }
 
 void
 if_enqueue_notify(struct iface_notification x)
 {
+  IFACE_ASSERT_LOCKED;
+
   WALK_TLIST(ifsub, s, &iface_sub_list)
     if_enqueue_notify_to(x, s);
 }
@@ -261,7 +359,7 @@ if_notify_change(unsigned c, struct iface *i)
 
   DBG("Interface change notification (%x) for %s\n", c, i->name);
 #ifdef LOCAL_DEBUG
-  if_dump(i);
+  if_dump_locked(i);
 #endif
 
   if (c & IF_CHANGE_DOWN)
@@ -323,10 +421,12 @@ if_change_flags(struct iface *i, uint flags)
 void
 if_delete(struct iface *old)
 {
+  IFACE_LOCK;
   struct iface f = {};
   strncpy(f.name, old->name, sizeof(f.name)-1);
   f.flags = IF_SHUTDOWN;
-  if_update(&f);
+  if_update_locked(&f);
+  IFACE_UNLOCK;
 }
 
 /**
@@ -347,6 +447,15 @@ if_delete(struct iface *old)
  */
 struct iface *
 if_update(struct iface *new)
+{
+  IFACE_LOCK;
+  struct iface *i = if_update_locked(new);
+  IFACE_UNLOCK;
+  return i;
+}
+
+struct iface *
+if_update_locked(struct iface *new)
 {
   struct iface *i;
   unsigned c;
@@ -354,7 +463,7 @@ if_update(struct iface *new)
   if (!new->master)
     new->master = &default_vrf;
 
-  WALK_LIST(i, iface_list)
+  WALK_LIST(i, global_iface_list)
     if (!strcmp(new->name, i->name))
       {
        new->flags = if_recalc_flags(new, new->flags);
@@ -389,17 +498,16 @@ if_update(struct iface *new)
   init_list(&i->neighbors);
 newif:
   i->flags |= IF_UPDATED | IF_TMP_DOWN;                /* Tmp down as we don't have addresses yet */
-  add_tail(&iface_list, &i->n);
+  add_tail(&global_iface_list, &i->n);
   return i;
 }
 
 void
 if_start_update(void)
 {
-  struct iface *i;
   struct ifa *a;
 
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     {
       i->flags &= ~IF_UPDATED;
       WALK_LIST(a, i->addrs)
@@ -407,8 +515,8 @@ if_start_update(void)
     }
 }
 
-void
-if_end_partial_update(struct iface *i)
+static void
+if_end_partial_update_locked(struct iface *i)
 {
   if (i->flags & IF_NEEDS_RECALC)
     if_recalc_preferred(i);
@@ -417,13 +525,20 @@ if_end_partial_update(struct iface *i)
     if_change_flags(i, i->flags & ~IF_TMP_DOWN);
 }
 
+void
+if_end_partial_update(struct iface *i)
+{
+  IFACE_LOCK;
+  if_end_partial_update_locked(i);
+  IFACE_UNLOCK;
+}
+
 void
 if_end_update(void)
 {
-  struct iface *i;
   struct ifa *a, *b;
 
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     {
       if (!(i->flags & IF_UPDATED))
        if_change_flags(i, (i->flags & ~IF_ADMIN_UP) | IF_SHUTDOWN);
@@ -432,55 +547,53 @@ if_end_update(void)
          WALK_LIST_DELSAFE(a, b, i->addrs)
            if (!(a->flags & IA_UPDATED))
              ifa_delete(a);
-         if_end_partial_update(i);
+         if_end_partial_update_locked(i);
        }
     }
 }
 
-void
-if_link(struct iface *i)
-{
-  if (i)
-    i->uc++;
-}
-
-void
-if_unlink(struct iface *i)
-{
-  if (i)
-    i->uc--;
-  /* TODO: Do some interface object cleanup */
-}
-
 static void
 iface_notify_hook(void *_s)
 {
   struct iface_subscription *s = _s;
 
+  IFACE_LOCK;
+
   while (!EMPTY_TLIST(ifnot, &s->queue))
   {
     struct iface_notification *n = THEAD(ifnot, &s->queue);
     debug("Process notify %d/%p (%p) to %p\n", n->type, n->a, n, s);
+    IFACE_UNLOCK;
+
     switch (n->type) {
       case IFNOT_ADDRESS:
        ifa_send_notify(s, n->flags, n->a);
+       IFACE_LOCK;
        ifa_unlink(n->a);
+       IFACE_UNLOCK;
        break;
       case IFNOT_INTERFACE:
        if_send_notify(s, n->flags, n->i);
+       IFACE_LOCK;
        if_unlink(n->i);
+       IFACE_UNLOCK;
        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;
     ifnot_rem_node(&s->queue, n);
     sl_free(n);
   }
+
+  IFACE_UNLOCK;
 }
 
 
@@ -494,6 +607,7 @@ iface_notify_hook(void *_s)
 void
 iface_subscribe(struct iface_subscription *s)
 {
+  IFACE_LOCK;
   ifsub_add_tail(&iface_sub_list, s);
   s->event = (event) {
     .hook = iface_notify_hook,
@@ -501,19 +615,34 @@ iface_subscribe(struct iface_subscription *s)
   };
 
   if (!s->if_notify && !s->ifa_notify) /* shortcut */
+  {
+    IFACE_UNLOCK;
     return;
+  }
 
   struct iface *i;
   DBG("Announcing interfaces to new protocol %s\n", p->name);
-  WALK_LIST(i, iface_list)
+  WALK_LIST(i, global_iface_list)
     {
-      if_send_notify(s, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
+      if_enqueue_notify_to(
+         (struct iface_notification) {
+         .type = IFNOT_INTERFACE,
+         .i = i,
+         .flags = IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0),
+         }, s);
 
       struct ifa *a;
       if (i->flags & IF_UP)
        WALK_LIST(a, i->addrs)
-         ifa_send_notify(s, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
+         if_enqueue_notify_to(
+             (struct iface_notification) {
+             .type = IFNOT_ADDRESS,
+             .a = a,
+             .flags = IF_CHANGE_CREATE | IF_CHANGE_UP,
+             }, s);
     }
+
+  IFACE_UNLOCK;
 }
 
 /**
@@ -523,6 +652,12 @@ iface_subscribe(struct iface_subscription *s)
 void
 iface_unsubscribe(struct iface_subscription *s)
 {
+  IFACE_LOCK;
+
+  struct proto *p = SKIP_BACK(struct proto, 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);
 
@@ -547,6 +682,10 @@ iface_unsubscribe(struct iface_subscription *s)
     ifnot_rem_node(&s->queue, n);
     sl_free(n);
   }
+
+  ASSERT_DIE(EMPTY_TLIST(proto_neigh, &p->neighbors));
+
+  IFACE_UNLOCK;
 }
 
 /**
@@ -558,16 +697,26 @@ iface_unsubscribe(struct iface_subscription *s)
  * if no such structure exists.
  */
 struct iface *
-if_find_by_index(unsigned idx)
+if_find_by_index_locked(unsigned idx)
 {
   struct iface *i;
 
-  WALK_LIST(i, iface_list)
+  WALK_LIST(i, global_iface_list)
     if (i->index == idx && !(i->flags & IF_SHUTDOWN))
       return i;
+
   return NULL;
 }
 
+struct iface *
+if_find_by_index(unsigned idx)
+{
+  IFACE_LOCK;
+  struct iface *i = if_find_by_index_locked(idx);
+  IFACE_UNLOCK;
+  return i;
+}
+
 /**
  * if_find_by_name - find interface by name
  * @name: interface name
@@ -581,9 +730,15 @@ if_find_by_name(const char *name)
 {
   struct iface *i;
 
-  WALK_LIST(i, iface_list)
+  IFACE_LOCK;
+  WALK_LIST(i, global_iface_list)
     if (!strcmp(i->name, name) && !(i->flags & IF_SHUTDOWN))
+    {
+      IFACE_UNLOCK;
       return i;
+    }
+
+  IFACE_UNLOCK;
   return NULL;
 }
 
@@ -592,9 +747,13 @@ if_get_by_name(const char *name)
 {
   struct iface *i;
 
-  WALK_LIST(i, iface_list)
+  IFACE_LOCK;
+  WALK_LIST(i, global_iface_list)
     if (!strcmp(i->name, name))
+    {
+      IFACE_UNLOCK;
       return i;
+    }
 
   /* No active iface, create a dummy */
   i = mb_allocz(if_pool, sizeof(struct iface));
@@ -602,7 +761,9 @@ if_get_by_name(const char *name)
   i->flags = IF_SHUTDOWN;
   init_list(&i->addrs);
   init_list(&i->neighbors);
-  add_tail(&iface_list, &i->n);
+  add_tail(&global_iface_list, &i->n);
+
+  IFACE_UNLOCK;
   return i;
 }
 
@@ -686,9 +847,7 @@ if_recalc_preferred(struct iface *i)
 void
 if_recalc_all_preferred_addresses(void)
 {
-  struct iface *i;
-
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
   {
     if_recalc_preferred(i);
 
@@ -715,6 +874,8 @@ ifa_same(struct ifa *a, struct ifa *b)
 struct ifa *
 ifa_update(struct ifa *a)
 {
+  IFACE_LOCK;
+
   struct iface *i = a->iface;
   struct ifa *b;
 
@@ -727,6 +888,8 @@ ifa_update(struct ifa *a)
            !((b->flags ^ a->flags) & (IA_SECONDARY | IA_PEER | IA_HOST)))
          {
            b->flags |= IA_UPDATED;
+
+           IFACE_UNLOCK;
            return b;
          }
        ifa_delete(b);
@@ -746,6 +909,8 @@ ifa_update(struct ifa *a)
   i->flags |= IF_NEEDS_RECALC;
   if (i->flags & IF_UP)
     ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
+
+  IFACE_UNLOCK;
   return b;
 }
 
@@ -763,6 +928,8 @@ ifa_delete(struct ifa *a)
   struct iface *i = a->iface;
   struct ifa *b;
 
+  IFACE_LOCK;
+
   WALK_LIST(b, i->addrs)
     if (ifa_same(b, a))
       {
@@ -787,43 +954,23 @@ ifa_delete(struct ifa *a)
          ifa_notify_change(IF_CHANGE_DOWN, b);
 
        ifa_unlink(b);
+       IFACE_UNLOCK;
        return;
       }
-}
-
-void ifa_link(struct ifa *a)
-{
-  if (a)
-  {
-    debug("ifa_link: %p %d\n", a, a->uc);
-    a->uc++;
-  }
-}
-
-void ifa_unlink(struct ifa *a)
-{
-  if (!a)
-    return;
-
-  debug("ifa_unlink: %p %d\n", a, a->uc);
-  if (--a->uc)
-    return;
 
-  if_unlink(a->iface);
-#if DEBUGGING
-  memset(a, 0x5b, sizeof(struct ifa));
-#endif
-  mb_free(a);
+  IFACE_UNLOCK;
 }
 
 u32
 if_choose_router_id(struct iface_patt *mask, u32 old_id)
 {
+  IFACE_LOCK;
+
   struct iface *i;
   struct ifa *a, *b;
 
   b = NULL;
-  WALK_LIST(i, iface_list)
+  WALK_LIST(i, global_iface_list)
     {
       if (!(i->flags & IF_ADMIN_UP) ||
          (i->flags & IF_SHUTDOWN))
@@ -850,6 +997,8 @@ if_choose_router_id(struct iface_patt *mask, u32 old_id)
        }
     }
 
+  IFACE_UNLOCK;
+
   if (!b)
     return 0;
 
@@ -870,10 +1019,11 @@ void
 if_init(void)
 {
   if_pool = rp_new(&root_pool, "Interfaces");
-  init_list(&iface_list);
+  init_list(&global_iface_list);
   iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
   strcpy(default_vrf.name, "default");
   neigh_init(if_pool);
+  iface_domain = DOMAIN_NEW(attrs, "Interfaces");
 }
 
 /*
@@ -995,11 +1145,10 @@ if_show_addr(struct ifa *a)
 void
 if_show(void)
 {
-  struct iface *i;
   struct ifa *a;
   char *type;
 
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     {
       if (i->flags & IF_SHUTDOWN)
        continue;
@@ -1039,10 +1188,8 @@ if_show(void)
 void
 if_show_summary(void)
 {
-  struct iface *i;
-
   cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     {
       byte a4[IPA_MAX_TEXT_LENGTH + 17];
       byte a6[IPA_MAX_TEXT_LENGTH + 17];
index a3f4f30a1134ff69ef2ad7c8ac6bc5837c10da04..05898a55a4434ed5720cc3efe0cc2121bafe4004 100644 (file)
@@ -9,13 +9,12 @@
 #ifndef _BIRD_IFACE_H_
 #define _BIRD_IFACE_H_
 
+#include "lib/locking.h"
 #include "lib/event.h"
 #include "lib/lists.h"
 #include "lib/tlists.h"
 #include "lib/ip.h"
 
-extern list iface_list;
-
 struct proto;
 struct pool;
 
@@ -112,6 +111,7 @@ void ifa_dump(struct ifa *);
 void if_show(void);
 void if_show_summary(void);
 struct iface *if_update(struct iface *);
+struct iface *if_update_locked(struct iface *);
 void if_delete(struct iface *old);
 struct ifa *ifa_update(struct ifa *);
 void ifa_delete(struct ifa *);
@@ -119,14 +119,16 @@ void if_start_update(void);
 void if_end_partial_update(struct iface *);
 void if_end_update(void);
 struct iface *if_find_by_index(unsigned);
+struct iface *if_find_by_index_locked(unsigned);
 struct iface *if_find_by_name(const char *);
 struct iface *if_get_by_name(const char *);
 void if_recalc_all_preferred_addresses(void);
 
-void if_link(struct iface *);
-void if_unlink(struct iface *);
-void ifa_link(struct ifa *);
-void ifa_unlink(struct ifa *);
+struct iface *if_walk_first(void);
+struct iface *if_walk_next(struct iface *);
+void if_walk_done(void);
+
+#define IFACE_WALK(_i) for (struct iface *_i = if_walk_first(); _i || (if_walk_done(), 0); _i = if_walk_next(_i))
 
 /* The Neighbor Cache */
 
@@ -161,9 +163,7 @@ typedef struct neighbor {
 
 neighbor *neigh_find(struct proto *p, ip_addr a, struct iface *ifa, uint flags);
 
-void neigh_dump(neighbor *);
 void neigh_dump_all(void);
-void neigh_prune(struct proto *);
 void neigh_if_up(struct iface *);
 void neigh_if_down(struct iface *);
 void neigh_if_link(struct iface *);
@@ -212,6 +212,7 @@ struct iface_subscription {
   TLIST_DEFAULT_NODE;
 
   event event;
+  event_list *target;
   TLIST_LIST(ifnot) queue;
 
   void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
index 88ac2860f7eb4d5541f53786ff40b31a7375b3f9..934cd35c3da70507f440781a1cea2ff7083bb827 100644 (file)
 static slab *neigh_slab;
 static list neigh_hash_table[NEIGH_HASH_SIZE], sticky_neigh_list;
 
+void if_link(struct iface *);
+void if_unlink(struct iface *);
+void ifa_link(struct ifa *);
+void ifa_unlink(struct ifa *);
+
+extern list global_iface_list;
+
+extern DOMAIN(attrs) iface_domain;
+
+#define IFACE_LOCK     LOCK_DOMAIN(attrs, iface_domain)
+#define IFACE_UNLOCK   UNLOCK_DOMAIN(attrs, iface_domain)
+#define IFACE_ASSERT_LOCKED    ASSERT_DIE(DOMAIN_IS_LOCKED(attrs, iface_domain))
+
 static inline uint
 neigh_hash(struct proto *p, ip_addr a, struct iface *i)
 {
@@ -152,7 +165,7 @@ if_connected_any(ip_addr a, struct iface *vrf, struct iface **iface, struct ifa
   *addr = NULL;
 
   /* Prefer SCOPE_HOST or longer prefix */
-  WALK_LIST(i, iface_list)
+  WALK_LIST(i, global_iface_list)
     if ((!vrf || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0))
       if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr)))
       {
@@ -210,6 +223,8 @@ if_intersect(struct iface *ia, struct iface *ib)
 neighbor *
 neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
 {
+  IFACE_LOCK;
+
   neighbor *n;
   int class, scope = -1;
   uint h = neigh_hash(p, a, iface);
@@ -218,26 +233,29 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
 
   WALK_LIST(n, neigh_hash_table[h])    /* Search the cache */
     if ((n->proto == p) && ipa_equal(n->addr, a) && (n->ifreq == iface))
+    {
+      IFACE_UNLOCK;
       return n;
+    }
 
   if (flags & NEF_IFACE)
   {
     if (ipa_nonzero(a) || !iface)
-      return NULL;
+      goto bad;
   }
   else
   {
     class = ipa_classify(a);
     if (class < 0)                     /* Invalid address */
-      return NULL;
+      goto bad;
     if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) ||
        (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && !iface) ||
        !(class & IADDR_HOST))
-      return NULL;                     /* Bad scope or a somecast */
+      goto bad;                                /* Bad scope or a somecast */
   }
 
   if ((flags & NEF_ONLINK) && !iface)
-      return NULL;
+    goto bad;
 
   if (iface)
   {
@@ -251,7 +269,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
   /* scope >= 0  <=>  iface != NULL */
 
   if ((scope < 0) && !(flags & NEF_STICKY))
-    return NULL;
+    goto bad;
 
   n = sl_allocz(neigh_slab);
   add_tail(&neigh_hash_table[h], &n->n);
@@ -267,7 +285,12 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
 
   neigh_link(n);
 
+  IFACE_UNLOCK;
   return n;
+
+bad:
+  IFACE_UNLOCK;
+  return NULL;
 }
 
 /**
@@ -276,7 +299,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
  *
  * This functions dumps the contents of a given neighbor entry to debug output.
  */
-void
+static void
 neigh_dump(neighbor *n)
 {
   debug("%p %I %s %s ", n, n->addr,
@@ -298,6 +321,8 @@ neigh_dump(neighbor *n)
 void
 neigh_dump_all(void)
 {
+  IFACE_LOCK;
+
   neighbor *n;
   int i;
 
@@ -306,11 +331,14 @@ neigh_dump_all(void)
     WALK_LIST(n, neigh_hash_table[i])
       neigh_dump(n);
   debug("\n");
+
+  IFACE_UNLOCK;
 }
 
 static inline void
 neigh_notify(neighbor *n)
 {
+  IFACE_ASSERT_LOCKED;
   if_enqueue_notify_to((struct iface_notification) { .type = IFNOT_NEIGHBOR, .n = n, }, &n->proto->iface_sub);
 }
 
@@ -352,12 +380,14 @@ neigh_down(neighbor *n)
 void
 neigh_link(neighbor *n)
 {
+  IFACE_ASSERT_LOCKED;
   n->uc++;
 }
 
 void
 neigh_unlink(neighbor *n)
 {
+  IFACE_ASSERT_LOCKED;
   if (--n->uc)
     return;
 
@@ -365,7 +395,7 @@ neigh_unlink(neighbor *n)
   proto_neigh_rem_node(&p->neighbors, n);
 
   if ((p->proto_state == PS_DOWN) && EMPTY_TLIST(proto_neigh, &p->neighbors))
-    ev_schedule(p->event);
+    proto_send_event(p, p->event);
 
   n->proto = NULL;
 
@@ -391,6 +421,8 @@ neigh_unlink(neighbor *n)
 void
 neigh_update(neighbor *n, struct iface *iface)
 {
+  IFACE_ASSERT_LOCKED;
+
   struct proto *p = n->proto;
   struct ifa *ifa = NULL;
   int scope = -1;
@@ -461,12 +493,13 @@ neigh_update(neighbor *n, struct iface *iface)
 void
 neigh_if_up(struct iface *i)
 {
+  IFACE_ASSERT_LOCKED;
   struct iface *ii;
   neighbor *n;
   node *x, *y;
 
   /* Update neighbors that might be better off with the new iface */
-  WALK_LIST(ii, iface_list)
+  WALK_LIST(ii, global_iface_list)
     if (!EMPTY_LIST(ii->neighbors) && (ii != i) && if_intersect(i, ii))
       WALK_LIST2_DELSAFE(n, x, y, ii->neighbors, if_n)
        neigh_update(n, i);
@@ -486,6 +519,7 @@ neigh_if_up(struct iface *i)
 void
 neigh_if_down(struct iface *i)
 {
+  IFACE_ASSERT_LOCKED;
   neighbor *n;
   node *x, *y;
 
@@ -503,6 +537,7 @@ neigh_if_down(struct iface *i)
 void
 neigh_if_link(struct iface *i)
 {
+  IFACE_ASSERT_LOCKED;
   neighbor *n;
   node *x, *y;
 
@@ -523,12 +558,13 @@ neigh_if_link(struct iface *i)
 void
 neigh_ifa_up(struct ifa *a)
 {
+  IFACE_ASSERT_LOCKED;
   struct iface *i = a->iface, *ii;
   neighbor *n;
   node *x, *y;
 
   /* Update neighbors that might be better off with the new ifa */
-  WALK_LIST(ii, iface_list)
+  WALK_LIST(ii, global_iface_list)
     if (!EMPTY_LIST(ii->neighbors) && ifa_intersect(a, ii))
       WALK_LIST2_DELSAFE(n, x, y, ii->neighbors, if_n)
        neigh_update(n, i);
@@ -541,6 +577,7 @@ neigh_ifa_up(struct ifa *a)
 void
 neigh_ifa_down(struct ifa *a)
 {
+  IFACE_ASSERT_LOCKED;
   struct iface *i = a->iface;
   neighbor *n;
   node *x, *y;
@@ -551,22 +588,6 @@ neigh_ifa_down(struct ifa *a)
       neigh_update(n, i);
 }
 
-/**
- * neigh_prune - prune neighbor cache
- *
- * neigh_prune() examines all neighbor entries cached and removes those
- * corresponding to inactive protocols. It's called whenever a protocol
- * is shut down to get rid of all its heritage.
- */
-void
-neigh_prune(struct proto *p)
-{
-  WALK_TLIST_DELSAFE(proto_neigh, n, &p->neighbors)
-    neigh_unlink(n);
-
-  ASSERT_DIE(EMPTY_TLIST(proto_neigh, &p->neighbors));
-}
-
 /**
  * neigh_init - initialize the neighbor cache.
  * @if_pool: resource pool to be used for neighbor entries.
index 877c8ab23841ad646c8a64bf2a5b658e54112657..aaa2a6023ba6c4a571b051be4a142e7f014b2921 100644 (file)
@@ -1142,7 +1142,6 @@ proto_event(void *ptr)
   if (p->do_stop)
   {
     iface_unsubscribe(&p->iface_sub);
-    neigh_prune(p);
 
     p->do_stop = 0;
   }
@@ -1219,6 +1218,8 @@ proto_start(struct proto *p)
   if (p->cf->loop_order != DOMAIN_ORDER(the_bird))
     p->loop = birdloop_new(p->pool, p->cf->loop_order, p->pool->name);
 
+  p->iface_sub.target = proto_event_list(p);
+
   PROTO_LOCKED_FROM_MAIN(p)
     proto_notify_state(p, (p->proto->start ? p->proto->start(p) : PS_UP));
 }
index c2de7599e9582afe6c5ca542e0658da54c36d9b6..86306180df21750954626d6421fc36a12bbcf01b 100644 (file)
@@ -1944,9 +1944,7 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b
 static void
 babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
 {
-  struct iface *iface;
-
-  WALK_LIST(iface, iface_list)
+  IFACE_WALK(iface)
   {
     if (p->p.vrf && p->p.vrf != iface->master)
       continue;
index 59255350860affd468cb593d1bfacbaa61e3e3a6..1919bccb0f829975fa4e31b6843a4697c4d18f97 100644 (file)
@@ -1225,10 +1225,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
 static void
 ospf_reconfigure_ifaces2(struct ospf_proto *p)
 {
-  struct iface *iface;
   struct ifa *a;
 
-  WALK_LIST(iface, iface_list)
+  IFACE_WALK(iface)
   {
     if (p->p.vrf && p->p.vrf != iface->master)
       continue;
@@ -1274,10 +1273,9 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
 static void
 ospf_reconfigure_ifaces3(struct ospf_proto *p)
 {
-  struct iface *iface;
   struct ifa *a;
 
-  WALK_LIST(iface, iface_list)
+  IFACE_WALK(iface)
   {
     if (p->p.vrf && p->p.vrf != iface->master)
       continue;
index a23b8945608227556bddde7efb92074901f08932..434155dc0dc01a5489e30067543d0f7198710ec7 100644 (file)
@@ -666,8 +666,7 @@ radv_reconfigure(struct proto *P, struct proto_config *CF)
   if (!old->propagate_routes && new->propagate_routes)
     channel_request_feeding(p->p.main_channel);
 
-  struct iface *iface;
-  WALK_LIST(iface, iface_list)
+  IFACE_WALK(iface)
   {
     if (p->p.vrf && p->p.vrf != iface->master)
       continue;
index e9aaf7b15901417d3fc14a2f48349cdb6ab469b2..97d1dd802b2a218ff90d8326f881ed1f73100c20 100644 (file)
@@ -807,9 +807,7 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
 static void
 rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
 {
-  struct iface *iface;
-
-  WALK_LIST(iface, iface_list)
+  IFACE_WALK(iface)
   {
     if (p->p.vrf && p->p.vrf != iface->master)
       continue;
index ca1c9e890689f74da984cf242a0bcd9a8d4b2dbb..e7b2147401e8ae66bc87db6fbadac109da4cc6b5 100644 (file)
@@ -277,14 +277,17 @@ krt_send_route(struct krt_proto *p, int cmd, const rte *e)
    */
   if (!i)
   {
-    WALK_LIST(j, iface_list)
+    j = if_walk_first();
+    while (j)
     {
       if (j->flags & IF_LOOPBACK)
       {
         i = j;
         break;
       }
+      j = if_walk_next(j);
     }
+    if_walk_done();
 
     if (!i)
     {
index 0609fde890fe4da20d37db0259f08dd086d7c8ff..b18cb899e38264f7f264e2e37db1fa438b089594 100644 (file)
@@ -1283,8 +1283,7 @@ kif_do_scan(struct kif_proto *p UNUSED)
       log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
 
   /* Re-resolve master interface for slaves */
-  struct iface *i;
-  WALK_LIST(i, iface_list)
+  IFACE_WALK(i)
     if (i->master_index)
     {
       struct iface f = {
@@ -1292,13 +1291,13 @@ kif_do_scan(struct kif_proto *p UNUSED)
        .mtu = i->mtu,
        .index = i->index,
        .master_index = i->master_index,
-       .master = if_find_by_index(i->master_index)
+       .master = if_find_by_index_locked(i->master_index)
       };
 
       if (f.master != i->master)
       {
        memcpy(f.name, i->name, sizeof(f.name));
-       if_update(&f);
+       if_update_locked(&f);
       }
     }