]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Interface updates are asynchronous
authorMaria Matejka <mq@ucw.cz>
Tue, 31 Jan 2023 12:07:46 +0000 (13:07 +0100)
committerMaria Matejka <mq@ucw.cz>
Thu, 2 Feb 2023 14:57:21 +0000 (15:57 +0100)
Instead of propagating interface updates as they are loaded from kernel,
they are enqueued and all the notifications are called from a
protocol-specific event. This change allows to break the locking loop
between protocols and interfaces.

Anyway, this change is based on v2 branch to keep the changes between v2
and v3 smaller.

15 files changed:
nest/iface.c
nest/iface.h
nest/neighbor.c
nest/proto.c
nest/protocol.h
nest/rt-dev.c
proto/babel/babel.c
proto/bfd/bfd.c
proto/bgp/bgp.c
proto/ospf/ospf.c
proto/perf/perf.c
proto/radv/radv.c
proto/rip/rip.c
proto/static/static.c
sysdep/unix/krt.c

index fc63dc75019bf9512e4556032f919a03fc17a6d0..740c18789a40c516f0ca3f6785ca8d65a37e4452 100644 (file)
@@ -34,6 +34,9 @@
 #include "conf/conf.h"
 #include "sysdep/unix/krt.h"
 
+
+static TLIST_LIST(ifsub) iface_sub_list;
+static slab *iface_sub_slab;
 static pool *if_pool;
 
 list iface_list;
@@ -140,13 +143,51 @@ if_copy(struct iface *to, struct iface *from)
   to->flags = from->flags | (to->flags & IF_TMP_DOWN);
   to->mtu = from->mtu;
   to->master_index = from->master_index;
-  to->master = from->master;
+
+  if_unlink(to->master);
+  if_link(to->master = from->master);
+}
+
+void
+if_enqueue_notify_to(struct iface_notification x, struct iface_subscription *s)
+{
+  switch (x.type) {
+    case IFNOT_ADDRESS:
+      if (!s->ifa_notify) return;
+      ifa_link(x.a);
+      break;
+    case IFNOT_INTERFACE:
+      if (!s->if_notify) return;
+      if_link(x.i);
+      break;
+    case IFNOT_NEIGHBOR:
+      if (!s->neigh_notify) return;
+      neigh_link(x.n);
+      break;
+    default:
+      bug("Unknown interface notification type: %d", x.type);
+  }
+
+  struct iface_notification *in = sl_alloc(iface_sub_slab);
+  *in = x;
+
+  ifnot_add_tail(&s->queue, in);
+  ev_schedule(&s->event);
+}
+
+void
+if_enqueue_notify(struct iface_notification x)
+{
+  WALK_TLIST(ifsub, s, &iface_sub_list)
+    if_enqueue_notify_to(x, s);
 }
 
 static inline void
-ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
+ifa_send_notify(struct iface_subscription *s, unsigned c, struct ifa *a)
 {
-  if (p->ifa_notify &&
+  struct proto *p = SKIP_BACK(struct proto, iface_sub, s);
+
+  if (s->ifa_notify &&
       (p->proto_state != PS_DOWN) &&
       (!p->vrf || p->vrf == a->iface->master))
     {
@@ -154,19 +195,21 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
        log(L_TRACE "%s < address %N on interface %s %s",
            p->name, &a->prefix, a->iface->name,
            (c & IF_CHANGE_UP) ? "added" : "removed");
-      p->ifa_notify(p, c, a);
+      s->ifa_notify(p, c, a);
     }
 }
 
 static void
 ifa_notify_change_(unsigned c, struct ifa *a)
 {
-  struct proto *p;
-
   DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
 
-  WALK_LIST(p, proto_list)
-    ifa_send_notify(p, c, a);
+  if_enqueue_notify((struct iface_notification) {
+       .type = IFNOT_ADDRESS,
+       .a = a,
+       .flags = c,
+      });
+
 }
 
 static inline void
@@ -182,9 +225,11 @@ ifa_notify_change(unsigned c, struct ifa *a)
 }
 
 static inline void
-if_send_notify(struct proto *p, unsigned c, struct iface *i)
+if_send_notify(struct iface_subscription *s, unsigned c, struct iface *i)
 {
-  if (p->if_notify &&
+  struct proto *p = SKIP_BACK(struct proto, iface_sub, s);
+
+  if (s->if_notify &&
       (p->proto_state != PS_DOWN) &&
       (!p->vrf || p->vrf == i->master))
     {
@@ -197,14 +242,13 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
            (c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
            (c & IF_CHANGE_CREATE) ? "created" :
            "sends unknown event");
-      p->if_notify(p, c, i);
+      s->if_notify(p, c, i);
     }
 }
 
 static void
 if_notify_change(unsigned c, struct iface *i)
 {
-  struct proto *p;
   struct ifa *a;
 
   if (i->flags & IF_JUST_CREATED)
@@ -225,8 +269,11 @@ if_notify_change(unsigned c, struct iface *i)
     WALK_LIST(a, i->addrs)
       ifa_notify_change_(IF_CHANGE_DOWN, a);
 
-  WALK_LIST(p, proto_list)
-    if_send_notify(p, c, i);
+  if_enqueue_notify((struct iface_notification) {
+       .type = IFNOT_INTERFACE,
+       .i = i,
+       .flags = c,
+      });
 
   if (c & IF_CHANGE_UP)
     WALK_LIST(a, i->addrs)
@@ -320,6 +367,7 @@ if_update(struct iface *new)
            new->llv6 = i->llv6;
            new->sysdep = i->sysdep;
            memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
+           memcpy(&new->neighbors, &i->neighbors, sizeof(i->neighbors));
            memcpy(i, new, sizeof(*i));
            i->flags &= ~IF_UP;         /* IF_TMP_DOWN will be added later */
            goto newif;
@@ -334,9 +382,10 @@ if_update(struct iface *new)
       }
   i = mb_alloc(if_pool, sizeof(struct iface));
   memcpy(i, new, sizeof(*i));
+  if_link(i->master);
   init_list(&i->addrs);
-newif:
   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);
   return i;
@@ -386,31 +435,116 @@ if_end_update(void)
     }
 }
 
+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;
+
+  while (!EMPTY_TLIST(ifnot, &s->queue))
+  {
+    struct iface_notification *n = THEAD(ifnot, &s->queue);
+    switch (n->type) {
+      case IFNOT_ADDRESS:
+       ifa_send_notify(s, n->flags, n->a);
+       ifa_unlink(n->a);
+       break;
+      case IFNOT_INTERFACE:
+       if_send_notify(s, n->flags, n->i);
+       if_unlink(n->i);
+       break;
+      case IFNOT_NEIGHBOR:
+       s->neigh_notify(n->n);
+       neigh_unlink(n->n);
+       break;
+      default:
+       bug("Bad interface notification type: %d", n->type);
+    }
+
+    ifnot_rem_node(&s->queue, n);
+    sl_free(n);
+  }
+}
+
+
 /**
- * if_feed_baby - advertise interfaces to a new protocol
- * @p: protocol to feed
+ * iface_subscribe - request interface updates
+ * @s: subscription structure
  *
  * When a new protocol starts, this function sends it a series
  * of notifications about all existing interfaces.
  */
 void
-if_feed_baby(struct proto *p)
+iface_subscribe(struct iface_subscription *s)
 {
-  struct iface *i;
-  struct ifa *a;
+  ifsub_add_tail(&iface_sub_list, s);
+  s->event = (event) {
+    .hook = iface_notify_hook,
+    .data = s,
+  };
 
-  if (!p->if_notify && !p->ifa_notify) /* shortcut */
+  if (!s->if_notify && !s->ifa_notify) /* shortcut */
     return;
+
+  struct iface *i;
   DBG("Announcing interfaces to new protocol %s\n", p->name);
   WALK_LIST(i, iface_list)
     {
-      if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
+      if_send_notify(s, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
+
+      struct ifa *a;
       if (i->flags & IF_UP)
        WALK_LIST(a, i->addrs)
-         ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
+         ifa_send_notify(s, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
     }
 }
 
+/**
+ * iface_unsubscribe - unsubscribe from interface updates
+ * @s: subscription structure
+ */
+void
+iface_unsubscribe(struct iface_subscription *s)
+{
+  ifsub_rem_node(&iface_sub_list, s);
+  ev_postpone(&s->event);
+
+  WALK_TLIST_DELSAFE(ifnot, n, &s->queue)
+  {
+    switch (n->type)
+    {
+      case IFNOT_ADDRESS:
+       ifa_unlink(n->a);
+       break;
+      case IFNOT_INTERFACE:
+       if_unlink(n->i);
+       break;
+      case IFNOT_NEIGHBOR:
+       neigh_unlink(n->n);
+       break;
+      default:
+       bug("Bad interface notification type: %d", n->type);
+    }
+
+    ifnot_rem_node(&s->queue, n);
+    sl_free(n);
+  }
+}
+
 /**
  * if_find_by_index - find interface by ifindex
  * @idx: ifindex
@@ -600,6 +734,8 @@ ifa_update(struct ifa *a)
 
   b = mb_alloc(if_pool, sizeof(struct ifa));
   memcpy(b, a, sizeof(struct ifa));
+  ifa_link(b);
+  if_link(i);
   add_tail(&i->addrs, &b->n);
   b->flags |= IA_UPDATED;
 
@@ -646,11 +782,29 @@ ifa_delete(struct ifa *a)
        if (i->flags & IF_UP)
          ifa_notify_change(IF_CHANGE_DOWN, b);
 
-       mb_free(b);
+       ifa_unlink(b);
        return;
       }
 }
 
+void ifa_link(struct ifa *a)
+{
+  if (a)
+    a->uc++;
+}
+
+void ifa_unlink(struct ifa *a)
+{
+  if (!a)
+    return;
+
+  if (--a->uc)
+    return;
+
+  if_unlink(a->iface);
+  mb_free(a);
+}
+
 u32
 if_choose_router_id(struct iface_patt *mask, u32 old_id)
 {
@@ -706,6 +860,7 @@ if_init(void)
 {
   if_pool = rp_new(&root_pool, "Interfaces");
   init_list(&iface_list);
+  iface_sub_slab = sl_new(if_pool, sizeof(struct iface_notification));
   strcpy(default_vrf.name, "default");
   neigh_init(if_pool);
 }
index fb27f99eaf6e76a433f1eb8cee2f941fff08e191..a3f4f30a1134ff69ef2ad7c8ac6bc5837c10da04 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _BIRD_IFACE_H_
 #define _BIRD_IFACE_H_
 
+#include "lib/event.h"
 #include "lib/lists.h"
 #include "lib/tlists.h"
 #include "lib/ip.h"
@@ -27,6 +28,7 @@ struct ifa {                          /* Interface address */
   ip_addr opposite;                    /* Opposite end of a point-to-point link */
   unsigned scope;                      /* Interface address scope */
   unsigned flags;                      /* Analogous to iface->flags */
+  unsigned uc;                         /* Use (link) count */
 };
 
 extern struct iface default_vrf;
@@ -45,6 +47,7 @@ struct iface {
   struct ifa *llv6;                    /* Primary link-local address for IPv6 */
   ip4_addr sysdep;                     /* Arbitrary IPv4 address for internal sysdep use */
   list neighbors;                      /* All neighbors on this interface */
+  unsigned uc;                         /* Use (link) count */
 };
 
 #define IF_UP 1                                /* Currently just IF_ADMIN_UP */
@@ -115,12 +118,15 @@ void ifa_delete(struct ifa *);
 void if_start_update(void);
 void if_end_partial_update(struct iface *);
 void if_end_update(void);
-void if_feed_baby(struct proto *);
 struct iface *if_find_by_index(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 *);
 
 /* The Neighbor Cache */
 
@@ -138,6 +144,7 @@ typedef struct neighbor {
   u16 flags;                           /* NEF_* flags */
   s16 scope;                           /* Address scope, -1 for unreachable neighbors,
                                           SCOPE_HOST when it's our own address */
+  uint uc;                             /* Use (link) count */
 } neighbor;
 
 #define TLIST_PREFIX proto_neigh
@@ -164,6 +171,63 @@ void neigh_ifa_up(struct ifa *a);
 void neigh_ifa_down(struct ifa *a);
 void neigh_init(struct pool *);
 
+void neigh_link(neighbor *);
+void neigh_unlink(neighbor *);
+
+/*
+ *     Notification mechanism
+ */
+
+#define TLIST_PREFIX ifnot
+#define TLIST_TYPE struct iface_notification
+#define TLIST_ITEM nn
+#define TLIST_WANT_WALK
+#define TLIST_WANT_ADD_TAIL
+
+struct iface_notification {
+  TLIST_DEFAULT_NODE;
+  enum {
+    IFNOT_INVALID,
+    IFNOT_ADDRESS,
+    IFNOT_INTERFACE,
+    IFNOT_NEIGHBOR,
+  } type;
+  unsigned flags;
+  union {
+    struct ifa *a;
+    struct iface *i;
+    neighbor *n;
+  };
+};
+
+#include "lib/tlists.h"
+
+#define TLIST_PREFIX ifsub
+#define TLIST_TYPE struct iface_subscription
+#define TLIST_ITEM n
+#define TLIST_WANT_WALK
+#define TLIST_WANT_ADD_TAIL
+
+struct iface_subscription {
+  TLIST_DEFAULT_NODE;
+
+  event event;
+  TLIST_LIST(ifnot) queue;
+
+  void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
+  void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
+  void (*neigh_notify)(struct neighbor *neigh);
+};
+
+#include "lib/tlists.h"
+
+void if_enqueue_notify(struct iface_notification);
+void if_enqueue_notify_to(struct iface_notification x, struct iface_subscription *s);
+
+void iface_flush_notifications(struct iface_subscription *);
+void iface_subscribe(struct iface_subscription *);
+void iface_unsubscribe(struct iface_subscription *);
+
 /*
  *     Interface Pattern Lists
  */
index c27db98947a4bb45f5fc16727d99a8497f0cde44..88ac2860f7eb4d5541f53786ff40b31a7375b3f9 100644 (file)
@@ -258,13 +258,15 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
   add_tail((scope >= 0) ? &iface->neighbors : &sticky_neigh_list, &n->if_n);
   proto_neigh_add_tail(&p->neighbors, n);
   n->addr = a;
-  n->ifa = addr;
-  n->iface = iface;
-  n->ifreq = ifreq;
+  ifa_link(n->ifa = addr);
+  if_link(n->iface = iface);
+  if_link(n->ifreq = ifreq);
   n->proto = p;
   n->flags = flags;
   n->scope = scope;
 
+  neigh_link(n);
+
   return n;
 }
 
@@ -309,19 +311,20 @@ neigh_dump_all(void)
 static inline void
 neigh_notify(neighbor *n)
 {
-  if (n->proto && n->proto->neigh_notify && (n->proto->proto_state != PS_STOP))
-    n->proto->neigh_notify(n);
+  if_enqueue_notify_to((struct iface_notification) { .type = IFNOT_NEIGHBOR, .n = n, }, &n->proto->iface_sub);
 }
 
 static void
 neigh_up(neighbor *n, struct iface *i, struct ifa *a, int scope)
 {
   DBG("Waking up sticky neighbor %I\n", n->addr);
-  n->iface = i;
-  n->ifa = a;
+  if_link(n->iface = i);
+  ifa_link(n->ifa = a);
+
   n->scope = scope;
 
-  rem_node(&n->if_n);
+  rem_node(&n->if_n); /* HACK: Here the neighbor is always in the sticky list,
+                        regardless whether it is sticky or not */
   add_tail(&i->neighbors, &n->if_n);
 
   neigh_notify(n);
@@ -331,25 +334,48 @@ static void
 neigh_down(neighbor *n)
 {
   DBG("Flushing neighbor %I on %s\n", n->addr, n->iface->name);
-  n->iface = NULL;
-  n->ifa = NULL;
+
   n->scope = -1;
 
   rem_node(&n->if_n);
   add_tail(&sticky_neigh_list, &n->if_n);
 
+  ifa_unlink(n->ifa);
+  n->ifa = NULL;
+
+  if_unlink(n->iface);
+  n->iface = NULL;
+
   neigh_notify(n);
 }
 
-static inline void
-neigh_free(neighbor *n)
+void
+neigh_link(neighbor *n)
 {
-  proto_neigh_rem_node(&n->proto->neighbors, n);
+  n->uc++;
+}
+
+void
+neigh_unlink(neighbor *n)
+{
+  if (--n->uc)
+    return;
+
+  struct proto *p = n->proto;
+  proto_neigh_rem_node(&p->neighbors, n);
+
+  if ((p->proto_state == PS_DOWN) && EMPTY_TLIST(proto_neigh, &p->neighbors))
+    ev_schedule(p->event);
+
   n->proto = NULL;
 
   rem_node(&n->n);
   rem_node(&n->if_n);
 
+  ifa_unlink(n->ifa);
+  if_unlink(n->iface);
+  if_unlink(n->ifreq);
+
   sl_free(n);
 }
 
@@ -399,7 +425,8 @@ neigh_update(neighbor *n, struct iface *iface)
   {
     if (ifa != n->ifa)
     {
-      n->ifa = ifa;
+      ifa_unlink(n->ifa);
+      ifa_link(n->ifa = ifa);
       neigh_notify(n);
     }
 
@@ -413,7 +440,7 @@ neigh_update(neighbor *n, struct iface *iface)
 
   if ((n->scope < 0) && !(n->flags & NEF_STICKY))
   {
-    neigh_free(n);
+    neigh_unlink(n);
     return;
   }
 
@@ -534,8 +561,10 @@ neigh_ifa_down(struct ifa *a)
 void
 neigh_prune(struct proto *p)
 {
-  while (!EMPTY_TLIST(proto_neigh, &p->neighbors))
-    neigh_free(THEAD(proto_neigh, &p->neighbors));
+  WALK_TLIST_DELSAFE(proto_neigh, n, &p->neighbors)
+    neigh_unlink(n);
+
+  ASSERT_DIE(EMPTY_TLIST(proto_neigh, &p->neighbors));
 }
 
 /**
index 2614943cbcb32bf385a83f3b8d1bbe294446822c..39e8b9997d8dbd33d71985a4609b2fea28f14131 100644 (file)
@@ -57,7 +57,11 @@ static inline void channel_reset_limit(struct channel_limit *l);
 
 
 static inline int proto_is_done(struct proto *p)
-{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
+{
+  return (p->proto_state == PS_DOWN)
+    && (p->active_channels == 0)
+    && EMPTY_TLIST(proto_neigh, &p->neighbors);
+}
 
 static inline int channel_is_active(struct channel *c)
 { return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
@@ -962,14 +966,18 @@ proto_event(void *ptr)
 
   if (p->do_start)
   {
-    if_feed_baby(p);
+    iface_subscribe(&p->iface_sub);
     p->do_start = 0;
   }
 
   if (p->do_stop)
   {
+    iface_unsubscribe(&p->iface_sub);
+    neigh_prune(p);
+
     p->do_stop = 0;
   }
+
   if (proto_is_done(p))
   {
     if (p->proto->cleanup)
@@ -1860,7 +1868,6 @@ proto_do_stop(struct proto *p)
   p->down_sched = 0;
   p->gr_recovery = 0;
 
-
   if (p->main_source)
   {
     rt_unlock_source(p->main_source);
@@ -1877,7 +1884,6 @@ static void
 proto_do_down(struct proto *p)
 {
   p->down_code = 0;
-  neigh_prune(p);
   rfree(p->pool);
   p->pool = NULL;
 
index 9fbe9158c3c9470312b54fb3d0d5615ad1355839..6d5714a744eb836dffe846db393b4ecc83c8e338 100644 (file)
@@ -171,6 +171,7 @@ struct proto {
   struct rte_src *main_source;         /* Primary route source */
   struct iface *vrf;                   /* Related VRF instance, NULL if global */
   TLIST_LIST(proto_neigh) neighbors;   /* List of neighbor structures */
+  struct iface_subscription iface_sub; /* Interface notification subscription */
 
   const char *name;                    /* Name of this instance (== cf->name) */
   u32 debug;                           /* Debugging flags */
@@ -210,10 +211,7 @@ struct proto {
    *      feed_end     Notify channel about finish of route feeding.
    */
 
-  void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
-  void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
   void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
-  void (*neigh_notify)(struct neighbor *neigh);
   int (*preexport)(struct channel *, struct rte *rt);
   void (*reload_routes)(struct channel *);
   void (*feed_begin)(struct channel *, int initial);
index 7932b8b7d039cc5ea3a8d7f9aaf834231b8bfdce..42b6b499563bb9b8f72d6388e8181c5cb53a1870 100644 (file)
@@ -141,8 +141,8 @@ dev_init(struct proto_config *CF)
   proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
   proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
 
-  P->if_notify = dev_if_notify;
-  P->ifa_notify = dev_ifa_notify;
+  P->iface_sub.if_notify = dev_if_notify;
+  P->iface_sub.ifa_notify = dev_ifa_notify;
 
   return P;
 }
index e1b31e86346419efb81877905eb4548e7c08a035..151359220cc4b24db8dbf26220d3e0b705770980 100644 (file)
@@ -2424,7 +2424,7 @@ babel_init(struct proto_config *CF)
   proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
   proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
 
-  P->if_notify = babel_if_notify;
+  P->iface_sub.if_notify = babel_if_notify;
   P->rt_notify = babel_rt_notify;
   P->preexport = babel_preexport;
   P->rte_better = babel_rte_better;
index 69e42f3d9aeb3bd6d66063efba11606226c172ea..b26559525c00652e7b3e8bce1ac8dd7baaf166e9 100644 (file)
@@ -1012,7 +1012,7 @@ bfd_init(struct proto_config *c)
 {
   struct proto *p = proto_new(c);
 
-  p->neigh_notify = bfd_neigh_notify;
+  p->iface_sub.neigh_notify = bfd_neigh_notify;
 
   return p;
 }
index 5b0569ae0122a30c00316d103f340e8fd28593d1..3531ce51ccce351e20122c2395f2976efa3f81b9 100644 (file)
@@ -1686,7 +1686,7 @@ bgp_init(struct proto_config *CF)
 
   P->rt_notify = bgp_rt_notify;
   P->preexport = bgp_preexport;
-  P->neigh_notify = bgp_neigh_notify;
+  P->iface_sub.neigh_notify = bgp_neigh_notify;
   P->reload_routes = bgp_reload_routes;
   P->feed_begin = bgp_feed_begin;
   P->feed_end = bgp_feed_end;
index ad4b2d14ddcb73bce601848e6b1b40cc87a8ad56..77a14b7a515a7248b59792ca74f5f07d56b537ab 100644 (file)
@@ -370,8 +370,8 @@ ospf_init(struct proto_config *CF)
   P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
 
   P->rt_notify = ospf_rt_notify;
-  P->if_notify = ospf_if_notify;
-  P->ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
+  P->iface_sub.if_notify = ospf_if_notify;
+  P->iface_sub.ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
   P->preexport = ospf_preexport;
   P->reload_routes = ospf_reload_routes;
   P->feed_begin = ospf_feed_begin;
index 75e405f0f88c2c0c16c26182491784f362835228..8941d582b1112269e4f4d4be4f08af63137f37dd 100644 (file)
@@ -266,7 +266,7 @@ perf_init(struct proto_config *CF)
 
   switch (p->mode) {
     case PERF_MODE_IMPORT:
-      P->ifa_notify = perf_ifa_notify;
+      P->iface_sub.ifa_notify = perf_ifa_notify;
       break;
     case PERF_MODE_EXPORT:
       P->rt_notify = perf_rt_notify;
index ee1da36c55d7e9dfd21cbf5e97d2d256af167db3..8a7440e69000ef85d0d615782e14b93dca2eeebc 100644 (file)
@@ -579,8 +579,8 @@ radv_init(struct proto_config *CF)
 
   P->preexport = radv_preexport;
   P->rt_notify = radv_rt_notify;
-  P->if_notify = radv_if_notify;
-  P->ifa_notify = radv_ifa_notify;
+  P->iface_sub.if_notify = radv_if_notify;
+  P->iface_sub.ifa_notify = radv_ifa_notify;
 
   return P;
 }
index 93b0d5280215b1ea3e7d3cf3353fccec686e40a7..abbd83f2a1c1eab673003d1cbd70873e4ae704cd 100644 (file)
@@ -1135,9 +1135,9 @@ rip_init(struct proto_config *CF)
 
   P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
 
-  P->if_notify = rip_if_notify;
+  P->iface_sub.if_notify = rip_if_notify;
   P->rt_notify = rip_rt_notify;
-  P->neigh_notify = rip_neigh_notify;
+  P->iface_sub.neigh_notify = rip_neigh_notify;
   P->reload_routes = rip_reload_routes;
   P->rte_better = rip_rte_better;
   P->rte_igp_metric = rip_rte_igp_metric;
index bb93305ed2fcc89d2d5ac8be316522be28b9d516..ba0984b50538ee7d6165bfe6d45eaf64e0864b84 100644 (file)
@@ -463,7 +463,7 @@ static_init(struct proto_config *CF)
 
   P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
 
-  P->neigh_notify = static_neigh_notify;
+  P->iface_sub.neigh_notify = static_neigh_notify;
   P->reload_routes = static_reload_routes;
   P->rte_better = static_rte_better;
   P->rte_mergable = static_rte_mergable;
index 7ec30eb0ae2f08ea2019915b573b6e6f87fde5b9..52822c3d7dc8181040c773d92530784c4aefdf07 100644 (file)
@@ -1046,7 +1046,7 @@ krt_init(struct proto_config *CF)
 
   p->p.preexport = krt_preexport;
   p->p.rt_notify = krt_rt_notify;
-  p->p.if_notify = krt_if_notify;
+  p->p.iface_sub.if_notify = krt_if_notify;
   p->p.reload_routes = krt_reload_routes;
   p->p.feed_end = krt_feed_end;