]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
MPLS Subsystem Proper Locking
authorMaria Matejka <mq@ucw.cz>
Thu, 23 Nov 2023 17:41:07 +0000 (18:41 +0100)
committerMaria Matejka <mq@ucw.cz>
Fri, 26 Jan 2024 13:42:44 +0000 (14:42 +0100)
Added also some debug lines if debug is on.

nest/mpls-internal.h
nest/mpls.c
nest/mpls.h
nest/rt-table.c
proto/bgp/bgp.c

index e5393b97bcad9d12a3b27d86ca774041ae529e31..1c6f380cd8979ec8ce16b5437e8d6fd61c79bad5 100644 (file)
 #include "nest/route.h"
 #include "nest/protocol.h"
 #include "nest/mpls.h"
+#include "lib/tlists.h"
 
 
+#define MPLS_DOMAIN_PUBLIC \
+  node n;                              /* Node in global list of MPLS domains (mpls_domains) */ \
+  const char *name;    \
+  DOMAIN(attrs) lock;  \
+
 struct mpls_domain {
-  node n;                              /* Node in global list of MPLS domains (mpls_domains) */
+  MPLS_DOMAIN_PUBLIC;
+  struct mpls_domain **locked_at;
   struct mpls_domain_config *cf;       /* Our config */
-  const char *name;
   pool *pool;                          /* Pool for the domain and associated objects */
 
   struct lmap labels;                  /* Bitmap of allocated labels */
@@ -31,30 +37,98 @@ struct mpls_domain {
   struct config *removed;              /* Deconfigured, waiting for zero use_count,
                                           while keeping config obstacle */
 
+  struct mpls_range *static_range;     /* Direct static range pointer */
   list ranges;                         /* List of label ranges (struct mpls_range) */
-  list handles;                                /* List of label handles (struct mpls_handle) */
+  event range_cleanup;                 /* Event for asynchronous cleanup of removed ranges */
 };
 
+struct mpls_domain_pub {
+  union {
+    struct { MPLS_DOMAIN_PUBLIC; };
+    struct mpls_domain priv;
+  };
+};
+
+#define mpls_domain_private mpls_domain
+#define MPLS_DOMAIN_LOCK(_obj, _pobj)  LOBJ_LOCK(_obj, _pobj, mpls_domain, attrs)
+#define MPLS_DOMAIN_LOCKED(_obj, _pobj)        LOBJ_LOCKED(_obj, _pobj, mpls_domain, attrs)
+LOBJ_UNLOCK_CLEANUP(mpls_domain, attrs);
+
+#define MPLS_DOMAIN_PRIV(_obj)         LOBJ_PRIV(_obj, attrs)
+#define MPLS_DOMAIN_PUB(_pobj)         SKIP_BACK(struct mpls_domain_pub, priv, (_pobj))
+
+#define MPLS_RANGE_PUBLIC \
+  node n;                              /* Node in mpls_domain.ranges */  \
+  DOMAIN(attrs) lock;                  /* Shared with the domain */      \
+
 struct mpls_range {
-  node n;                              /* Node in mpls_domain.ranges */
+  MPLS_RANGE_PUBLIC;
+  struct mpls_range **locked_at;
   struct mpls_range_config *cf;                /* Our config */
   const char *name;
 
+  struct mpls_domain *domain;
+  list handles;                                /* List of label handles (struct mpls_handle) */
+
   uint lo, hi;                         /* Label range interval */
   uint label_count;                    /* Number of allocated labels */
   uint use_count;                      /* Reference counter */
   u8 removed;                          /* Deconfigured, waiting for zero use_count */
 };
 
+struct mpls_range_pub {
+  union {
+    struct { MPLS_RANGE_PUBLIC; };
+    struct mpls_range priv;
+  };
+};
+
+#define mpls_range_private mpls_range
+#define MPLS_RANGE_LOCK(_obj, _pobj)   LOBJ_LOCK(_obj, _pobj, mpls_range, attrs)
+#define MPLS_RANGE_LOCKED(_obj, _pobj) LOBJ_LOCKED(_obj, _pobj, mpls_range, attrs)
+LOBJ_UNLOCK_CLEANUP(mpls_range, attrs);
+
+#define MPLS_RANGE_PRIV(_obj)          LOBJ_PRIV(_obj, attrs)
+#define MPLS_RANGE_PUB(_pobj)          SKIP_BACK(struct mpls_range_pub, priv, (_pobj))
+
+#define MPLS_HANDLE_PUBLIC \
+  node n;                              /* Node in mpls_domain.handles */       \
+  const char *name;                    /* Shared with the range */             \
+  DOMAIN(attrs) lock;                  /* Shared with the domain */            \
+
 struct mpls_handle {
-  node n;                              /* Node in mpls_domain.handles */
+  MPLS_HANDLE_PUBLIC;
+  struct mpls_handle **locked_at;
 
   struct mpls_range *range;            /* Associated range, keeping reference */
   uint label_count;                    /* Number of allocated labels */
 };
 
-uint mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
-void mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
-void mpls_move_label(struct mpls_domain *m, struct mpls_handle *fh, struct mpls_handle *th, uint n);
+struct mpls_handle_pub {
+  union {
+    struct { MPLS_HANDLE_PUBLIC; };
+    struct mpls_handle priv;
+  };
+};
+
+#define mpls_handle_private mpls_handle
+#define MPLS_HANDLE_LOCK(_obj, _pobj)  LOBJ_LOCK(_obj, _pobj, mpls_handle, attrs)
+#define MPLS_HANDLE_LOCKED(_obj, _pobj)        LOBJ_LOCKED(_obj, _pobj, mpls_handle, attrs)
+LOBJ_UNLOCK_CLEANUP(mpls_handle, attrs);
+
+#define MPLS_HANDLE_PRIV(_obj)         LOBJ_PRIV(_obj, attrs)
+#define MPLS_HANDLE_PUB(_pobj)         SKIP_BACK(struct mpls_handle_pub, priv, (_pobj))
+
+uint mpls_new_label(struct mpls_handle *h, uint n);
+void mpls_free_label(struct mpls_handle *h, uint n);
+void mpls_move_label(struct mpls_handle *fh, struct mpls_handle *th, uint n);
+
+void mpls_lock_domain(struct mpls_domain *m);
+void mpls_unlock_domain(struct mpls_domain *m);
+
+void mpls_lock_range(struct mpls_range *m);
+void mpls_unlock_range(struct mpls_range *m);
+
+void mpls_revive_fec(struct mpls_fec *);
 
 #endif
index 2cc3e04e96017ee2babe3b3cfb93254a1e0ed294..c3697a45e8947ceab3b15eef53dafeaf56383e86 100644 (file)
@@ -90,7 +90,10 @@ static struct mpls_range *mpls_new_range(struct mpls_domain *m, struct mpls_rang
 static struct mpls_range *mpls_find_range_(list *l, const char *name);
 static int mpls_reconfigure_range(struct mpls_domain *m, struct mpls_range *r, struct mpls_range_config *cf);
 static void mpls_remove_range(struct mpls_range *r);
+static void mpls_cleanup_ranges(void *_domain);
 
+static void mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
+static void mpls_fec_map_cleanup(void *_m);
 
 /*
  *     MPLS domain
@@ -115,6 +118,7 @@ union mpls_global_public {
 void
 mpls_init(void)
 {
+  mpls_global.lock = the_bird_domain;
   init_list(&MPLS_GLOBAL->domains);
 }
 
@@ -197,11 +201,18 @@ mpls_domain_postconfig(struct mpls_domain_config *cf UNUSED)
   }
 }
 
-static struct mpls_domain *
+static struct mpls_domain_pub *
 mpls_new_domain(struct mpls_domain_config *cf)
 {
-  struct pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "MPLS domain");
-  struct mpls_domain *m = mb_allocz(p, sizeof(struct mpls_domain));
+  ASSERT_THE_BIRD_LOCKED;
+
+  DOMAIN(attrs) dom = DOMAIN_NEW(attrs);
+  LOCK_DOMAIN(attrs, dom);
+
+  struct pool *p = rp_newf(&root_pool, dom.attrs, "MPLS domain %s", cf->name);
+  struct mpls_domain_pub *mpub = mb_allocz(p, sizeof(struct mpls_domain_pub));
+  mpub->lock = dom;
+  struct mpls_domain *m = LOBJ_PRIV(mpub, attrs);
 
   m->cf = cf;
   m->name = cf->name;
@@ -211,22 +222,30 @@ mpls_new_domain(struct mpls_domain_config *cf)
   lmap_set(&m->labels, 0);
 
   init_list(&m->ranges);
-  init_list(&m->handles);
 
   struct mpls_range_config *rc;
   WALK_LIST(rc, cf->ranges)
-    mpls_new_range(m, rc);
+  {
+    struct mpls_range *r = mpls_new_range(m, rc);
+    if (rc == cf->static_range)
+      m->static_range = r;
+  }
+
+  m->range_cleanup = (event) { .hook = mpls_cleanup_ranges, .data = m };
 
   add_tail(&MPLS_GLOBAL->domains, &m->n);
-  cf->domain = m;
+  mpls_lock_domain(m);
 
-  return m;
+  UNLOCK_DOMAIN(attrs, dom);
+
+  cf->domain = mpub;
+  return mpub;
 }
 
-static struct mpls_domain *
+static struct mpls_domain_pub *
 mpls_find_domain_(list *l, const char *name)
 {
-  struct mpls_domain *m;
+  struct mpls_domain_pub *m;
 
   WALK_LIST(m, *l)
     if (!strcmp(m->name, name))
@@ -236,9 +255,12 @@ mpls_find_domain_(list *l, const char *name)
 }
 
 static int
-mpls_reconfigure_domain(struct mpls_domain *m, struct mpls_domain_config *cf)
+mpls_reconfigure_domain(struct mpls_domain_pub *mpub, struct mpls_domain_config *cf)
 {
-  cf->domain = m;
+  cf->domain = mpub;
+
+  MPLS_DOMAIN_LOCK(mpub, m);
+
   m->cf->domain = NULL;
   m->cf = cf;
   m->name = cf->name;
@@ -275,17 +297,24 @@ mpls_reconfigure_domain(struct mpls_domain *m, struct mpls_domain_config *cf)
 }
 
 static void
-mpls_free_domain(struct mpls_domain *m)
+mpls_free_domain(void *_m)
 {
+  ASSERT_THE_BIRD_LOCKED;
+
+  struct mpls_domain *m = _m;
+  DOMAIN(attrs) dom = m->lock;
+  LOCK_DOMAIN(attrs, dom);
+
   ASSERT(m->use_count == 0);
   ASSERT(m->label_count == 0);
-  ASSERT(EMPTY_LIST(m->handles));
+  ASSERT(EMPTY_LIST(m->ranges));
 
   struct config *cfg = m->removed;
 
   m->cf->domain = NULL;
   rem_node(&m->n);
   rfree(m->pool);
+  UNLOCK_DOMAIN(attrs, dom);
 
   config_del_obstacle(cfg);
 }
@@ -296,8 +325,12 @@ mpls_remove_domain(struct mpls_domain *m, struct config *cfg)
   m->removed = cfg;
   config_add_obstacle(cfg);
 
-  if (!m->use_count)
-    mpls_free_domain(m);
+  struct mpls_range *r, *rnext;
+  WALK_LIST_DELSAFE(r, rnext, m->ranges)
+    if (!r->removed)
+      mpls_remove_range(r);
+
+  mpls_unlock_domain(m);
 }
 
 void
@@ -313,7 +346,7 @@ mpls_unlock_domain(struct mpls_domain *m)
 
   m->use_count--;
   if (!m->use_count && m->removed)
-    mpls_free_domain(m);
+    ev_new_send(&main_birdloop, m->pool, mpls_free_domain, m);
 }
 
 void
@@ -333,7 +366,7 @@ mpls_commit(struct config *new, struct config *old)
   struct mpls_domain_config *mc;
   WALK_LIST(mc, new->mpls_domains)
   {
-    struct mpls_domain *m = mpls_find_domain_(&old_domains, mc->name);
+    struct mpls_domain_pub *m = mpls_find_domain_(&old_domains, mc->name);
 
     if (m && mpls_reconfigure_domain(m, mc))
     {
@@ -378,16 +411,26 @@ mpls_range_config_new(struct mpls_domain_config *mc, struct symbol *s)
 static struct mpls_range *
 mpls_new_range(struct mpls_domain *m, struct mpls_range_config *cf)
 {
-  struct mpls_range *r = mb_allocz(m->pool, sizeof(struct mpls_range));
+  struct mpls_range_pub *rpub = mb_allocz(m->pool, sizeof(struct mpls_range_pub));
+  rpub->lock = m->lock;
+
+  struct mpls_range *r = LOBJ_PRIV(rpub, attrs);
+
+  r->domain = m;
+  mpls_lock_domain(m);
 
   r->cf = cf;
   r->name = cf->name;
   r->lo = cf->start;
   r->hi = cf->start + cf->length;
 
+  init_list(&r->handles);
+
   add_tail(&m->ranges, &r->n);
-  cf->range = r;
+  cf->range = rpub;
 
+  DBGL("Lock range %p (new)", r);
+  mpls_lock_range(r);
   return r;
 }
 
@@ -412,7 +455,7 @@ mpls_reconfigure_range(struct mpls_domain *m, struct mpls_range *r, struct mpls_
   if ((cf->start > r->lo) || (cf->start + cf->length <= last))
     return 0;
 
-  cf->range = r;
+  cf->range = MPLS_RANGE_PUB(r);
   r->cf->range = NULL;
   r->cf = cf;
   r->name = cf->name;
@@ -425,13 +468,30 @@ mpls_reconfigure_range(struct mpls_domain *m, struct mpls_range *r, struct mpls_
 static void
 mpls_free_range(struct mpls_range *r)
 {
+  /* Must always run in an asynchronous context from main loop */
+  ASSERT_THE_BIRD_LOCKED;
+
   ASSERT(r->use_count == 0);
   ASSERT(r->label_count == 0);
 
+  mpls_unlock_domain(r->domain);
+
   rem_node(&r->n);
   mb_free(r);
 }
 
+static void mpls_cleanup_ranges(void *_domain)
+{
+  MPLS_DOMAIN_LOCK((struct mpls_domain_pub *) _domain, m);
+
+  struct mpls_range *r, *rnext;
+  WALK_LIST_BACKWARDS_DELSAFE(r, rnext, m->ranges)
+    if (!r->removed)
+      return;
+    else if (!r->use_count)
+      mpls_free_range(r);
+}
+
 static void
 mpls_remove_range(struct mpls_range *r)
 {
@@ -441,8 +501,8 @@ mpls_remove_range(struct mpls_range *r)
   r->cf->range = NULL;
   r->cf = NULL;
 
-  if (!r->use_count)
-    mpls_free_range(r);
+  DBGL("Unlock range %p (remove)", r);
+  mpls_unlock_range(r);
 }
 
 void
@@ -458,7 +518,7 @@ mpls_unlock_range(struct mpls_range *r)
 
   r->use_count--;
   if (!r->use_count && r->removed)
-    mpls_free_range(r);
+    ev_send_loop(&main_birdloop, &r->domain->range_cleanup);
 }
 
 
@@ -467,23 +527,28 @@ mpls_unlock_range(struct mpls_range *r)
  */
 
 struct mpls_handle *
-mpls_new_handle(struct mpls_domain *m, struct mpls_range *r)
+mpls_new_handle(struct mpls_range *r)
 {
+  struct mpls_domain *m = r->domain;
+
   struct mpls_handle *h = mb_allocz(m->pool, sizeof(struct mpls_handle));
+  h->lock = m->lock;
 
+  DBGL("Lock range %p (new handle %p)", r, h);
+  mpls_lock_range(r);
   h->range = r;
-  mpls_lock_range(h->range);
 
-  add_tail(&m->handles, &h->n);
+  add_tail(&r->handles, &h->n);
 
   return h;
 }
 
 void
-mpls_free_handle(struct mpls_domain *m UNUSED, struct mpls_handle *h)
+mpls_free_handle(struct mpls_handle *h)
 {
   ASSERT(h->label_count == 0);
 
+  DBGL("Unlock range %p (free handle %p)", h->range, h);
   mpls_unlock_range(h->range);
   rem_node(&h->n);
   mb_free(h);
@@ -495,9 +560,10 @@ mpls_free_handle(struct mpls_domain *m UNUSED, struct mpls_handle *h)
  */
 
 uint
-mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
+mpls_new_label(struct mpls_handle *h, uint n)
 {
   struct mpls_range *r = h->range;
+  struct mpls_domain *m = r->domain;
 
   if (!n)
     n = lmap_first_zero_in_range(&m->labels, r->lo, r->hi);
@@ -514,9 +580,10 @@ mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
 }
 
 void
-mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
+mpls_free_label(struct mpls_handle *h, uint n)
 {
   struct mpls_range *r = h->range;
+  struct mpls_domain *m = r->domain;
 
   ASSERT(lmap_test(&m->labels, n));
   lmap_clear(&m->labels, n);
@@ -532,10 +599,13 @@ mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
 }
 
 void
-mpls_move_label(struct mpls_domain *m, struct mpls_handle *fh, struct mpls_handle *th, uint n)
+mpls_move_label(struct mpls_handle *fh, struct mpls_handle *th, uint n)
 {
   struct mpls_range *fr = fh->range;
+  struct mpls_domain *m = fr->domain;
+
   struct mpls_range *tr = th->range;
+  ASSERT_DIE(tr->domain == m);
 
   ASSERT(lmap_test(&m->labels, n));
   ASSERT((n >= fr->lo) && (n < fr->hi));
@@ -562,22 +632,23 @@ mpls_channel_init(struct channel *C, struct channel_config *CC)
   struct mpls_channel *c = (void *) C;
   struct mpls_channel_config *cc = (void *) CC;
 
-  c->domain = cc->domain->domain;
-  c->range = cc->range->range;
-  c->label_policy = cc->label_policy;
-  c->rts = cc->rts;
+  if (cc->rts)
+  {
+    c->domain = cc->domain->domain;
+    c->range = cc->range->range;
+    c->label_policy = cc->label_policy;
+    c->rts = cc->rts;
+  }
 }
 
 static int
 mpls_channel_start(struct channel *C)
 {
   struct mpls_channel *c = (void *) C;
+  if (!c->rts)
+    return 0;
 
-  mpls_lock_domain(c->domain);
-  mpls_lock_range(c->range);
-
-  ASSERT_DIE(c->rts);
-  c->mpls_map = mpls_fec_map_new(C->proto->pool, C, c->rts);
+  c->mpls_map = mpls_fec_map_new(C->proto->pool, C->proto->loop, C, c->rts);
 
   return 0;
 }
@@ -587,6 +658,8 @@ static void
 mpls_channel_shutdown(struct channel *C)
 {
   struct mpls_channel *c = (void *) C;
+  if (!c->rts)
+    return;
 
 }
 */
@@ -595,12 +668,11 @@ static void
 mpls_channel_cleanup(struct channel *C)
 {
   struct mpls_channel *c = (void *) C;
+  if (!c->rts)
+    return;
 
   mpls_fec_map_free(c->mpls_map);
   c->mpls_map = NULL;
-
-  mpls_unlock_range(c->range);
-  mpls_unlock_domain(c->domain);
 }
 
 static int
@@ -615,13 +687,21 @@ mpls_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impo
   if (new->range->range != c->range)
   {
     if (c->c.channel_state != CS_DOWN)
-      mpls_unlock_range(c->range);
+      MPLS_RANGE_LOCKED(c->range, r)
+      {
+       DBGL("Unlock range %p (channel %p)", r, c);
+       mpls_unlock_range(r);
+      }
 
     c->range = new->range->range;
     *import_changed = 1;
 
     if (c->c.channel_state != CS_DOWN)
-      mpls_lock_range(c->range);
+      MPLS_RANGE_LOCKED(c->range, r)
+      {
+       DBGL("Lock range %p (channel %p)", r, c);
+       mpls_lock_range(r);
+      }
   }
 
   if (new->label_policy != c->label_policy)
@@ -705,19 +785,24 @@ static void mpls_withdraw_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
 static struct ea_storage * mpls_get_key_attrs(struct mpls_fec_map *m, ea_list *src);
 
 struct mpls_fec_map *
-mpls_fec_map_new(pool *pp, struct channel *C, uint rts)
+mpls_fec_map_new(pool *pp, struct birdloop *loop, struct channel *C, uint rts)
 {
-  struct pool *p = rp_new(pp, the_bird_domain.the_bird, "MPLS FEC map");
+  struct pool *p = rp_new(pp, pp->domain, "MPLS FEC map");
   struct mpls_fec_map *m = mb_allocz(p, sizeof(struct mpls_fec_map));
   struct mpls_channel *c = (void *) C;
 
+  DBGL("New FEC Map %p", m);
+
   m->pool = p;
+  m->loop = loop;
+  m->cleanup_event = ev_new_init(p, mpls_fec_map_cleanup, m);
   m->channel = C;
+  channel_add_obstacle(C);
+  ev_send_loop(loop, m->cleanup_event);
 
   m->domain = c->domain;
-  mpls_lock_domain(m->domain);
-
-  m->handle = mpls_new_handle(c->domain, c->range);
+  MPLS_RANGE_LOCKED(c->range, r)
+    m->handle = MPLS_HANDLE_PUB(mpls_new_handle(r));
 
   /* net_hash and rta_hash are initialized on-demand */
   HASH_INIT(m->label_hash, m->pool, 4);
@@ -732,21 +817,28 @@ mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
 {
   struct mpls_channel *c = (void *) C;
 
+  MPLS_DOMAIN_LOCK(m->domain, domain);
+
+  struct mpls_handle *dh = MPLS_HANDLE_PRIV(m->handle);
+  struct mpls_handle *sh = m->static_handle ? MPLS_HANDLE_PRIV(m->static_handle) : NULL;
+
+  struct mpls_range *new_range = MPLS_RANGE_PRIV(c->range);
+
   struct mpls_handle *old_d = NULL;
   struct mpls_handle *old_s = NULL;
 
   /* Reallocate dynamic handle */
-  if (m->handle->range != c->range)
+  if (dh->range != new_range)
   {
-    old_d = m->handle;
-    m->handle = mpls_new_handle(m->domain, c->range);
+    old_d = dh;
+    m->handle = MPLS_HANDLE_PUB(mpls_new_handle(new_range));
   }
 
   /* Reallocate static handle */
-  if (m->static_handle && (m->static_handle->range != m->domain->cf->static_range->range))
+  if (sh && (sh->range != domain->static_range))
   {
-    old_s = m->static_handle;
-    m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
+    old_s = sh;
+    m->static_handle = MPLS_HANDLE_PUB(mpls_new_handle(domain->static_range));
   }
 
   /* Skip rest if there is no change */
@@ -765,11 +857,14 @@ mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
       continue;
 
     /* Try new handle for the FEC */
-    struct mpls_handle *new = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
+    struct mpls_handle_pub *new_pub = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
+    struct mpls_handle *new = MPLS_HANDLE_PRIV(new_pub);
+    struct mpls_handle *old = MPLS_HANDLE_PRIV(fec->handle);
+
     if ((fec->label >= new->range->lo) && (fec->label < new->range->hi))
     {
-      mpls_move_label(m->domain, fec->handle, new, fec->label);
-      fec->handle = new;
+      mpls_move_label(old, new, fec->label);
+      fec->handle = new_pub;
       continue;
     }
 
@@ -782,15 +877,36 @@ mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
   /* Remove old unused handles */
 
   if (old_d && !old_d->label_count)
-    mpls_free_handle(m->domain, old_d);
+    mpls_free_handle(old_d);
 
   if (old_s && !old_s->label_count)
-    mpls_free_handle(m->domain, old_s);
+    mpls_free_handle(old_s);
+}
+
+static void
+mpls_fec_map_cleanup(void *_m)
+{
+  struct mpls_fec_map *m = _m;
+  _Bool finished = (m->channel->channel_state == CS_STOP);
+  HASH_WALK_DELSAFE(m->label_hash, next_l, fec)
+    if (lfuc_finished(&fec->uc))
+      mpls_free_fec(m, fec);
+    else
+      finished = 0;
+  HASH_WALK_DELSAFE_END;
+
+  if (finished)
+  {
+    ev_postpone(m->cleanup_event);
+    channel_del_obstacle(m->channel);
+  }
 }
 
 void
 mpls_fec_map_free(struct mpls_fec_map *m)
 {
+  DBGL("Free Whole FEC Map %p", m);
+
   /* Free stored rtas */
   if (m->attrs_hash.data)
   {
@@ -802,21 +918,24 @@ mpls_fec_map_free(struct mpls_fec_map *m)
     HASH_WALK_END;
   }
 
+  MPLS_DOMAIN_LOCK(m->domain, domain);
+
   /* Free allocated labels */
   HASH_WALK(m->label_hash, next_l, fec)
   {
-    mpls_free_label(m->domain, fec->handle, fec->label);
+    struct mpls_handle *h = MPLS_HANDLE_PRIV(fec->handle);
+    mpls_free_label(h, fec->label);
 
-    if (!fec->policy && !fec->handle->label_count)
-      mpls_free_handle(m->domain, fec->handle);
+    DBGL("Handle %p policy %d label count %d", fec->policy, h->label_count);
+    if (!fec->policy && !h->label_count)
+      mpls_free_handle(h);
   }
   HASH_WALK_END;
 
   if (m->static_handle)
-    mpls_free_handle(m->domain, m->static_handle);
+    mpls_free_handle(MPLS_HANDLE_PRIV(m->static_handle));
 
-  mpls_free_handle(m->domain, m->handle);
-  mpls_unlock_domain(m->domain);
+  mpls_free_handle(MPLS_HANDLE_PRIV(m->handle));
 
   rfree(m->pool);
 }
@@ -839,31 +958,57 @@ mpls_find_fec_by_label(struct mpls_fec_map *m, u32 label)
   return HASH_FIND(m->label_hash, LABEL, label);
 }
 
+struct mpls_fec *
+mpls_new_fec(struct mpls_fec_map *m, u8 net_type, u32 label)
+{
+  struct mpls_fec *fec = sl_allocz(mpls_slab(m, net_type));
+
+  fec->map = m;
+  fec->label = label;
+
+  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
+
+  /* Temporarily lock FEC */
+  lfuc_init(&fec->uc);
+
+  return fec;
+}
+
 struct mpls_fec *
 mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label)
 {
   struct mpls_fec *fec = HASH_FIND(m->label_hash, LABEL, label);
 
   if (fec)
-    return (fec->policy == MPLS_POLICY_STATIC) ? fec : NULL;
+  {
+    if (fec->policy == MPLS_POLICY_STATIC)
+      return NULL;
 
-  if (!m->static_handle)
-    m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
+    mpls_revive_fec(fec);
+    return fec;
+  }
 
-  label = mpls_new_label(m->domain, m->static_handle, label);
+  MPLS_DOMAIN_LOCKED(m->domain, domain)
+  {
+    struct mpls_handle *h;
 
-  if (!label)
-    return NULL;
+    if (m->static_handle)
+      h = MPLS_HANDLE_PRIV(m->static_handle);
+    else
+      m->static_handle = MPLS_HANDLE_PUB(h = mpls_new_handle(domain->static_range));
 
-  fec = sl_allocz(mpls_slab(m, 0));
+    label = mpls_new_label(h, label);
+
+    if (!label)
+      return NULL;
+  }
+
+  fec = mpls_new_fec(m, 0, label);
 
-  fec->label = label;
   fec->policy = MPLS_POLICY_STATIC;
   fec->handle = m->static_handle;
 
-  DBG("New FEC lab %u\n", fec->label);
-
-  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
+  DBGL("New FEC lab %u", fec->label);
 
   return fec;
 }
@@ -878,27 +1023,30 @@ mpls_get_fec_by_net(struct mpls_fec_map *m, const net_addr *net, u32 path_id)
   struct mpls_fec *fec = HASH_FIND(m->net_hash, NET, net, path_id, hash);
 
   if (fec)
+  {
+    mpls_revive_fec(fec);
     return fec;
+  }
 
-  u32 label = mpls_new_label(m->domain, m->handle, 0);
+  u32 label = 0;
+  MPLS_HANDLE_LOCKED(m->handle, h)
+    label = mpls_new_label(h, 0);
 
   if (!label)
     return NULL;
 
-  fec = sl_allocz(mpls_slab(m, net->type));
+  fec = mpls_new_fec(m, net->type, label);
 
   fec->hash = hash;
   fec->path_id = path_id;
   net_copy(fec->net, net);
 
-  fec->label = label;
   fec->policy = MPLS_POLICY_PREFIX;
   fec->handle = m->handle;
 
-  DBG("New FEC net %u\n", fec->label);
+  DBGL("New FEC net %u", fec->label);
 
   HASH_INSERT2(m->net_hash, NET, m->pool, fec);
-  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
 
   return fec;
 }
@@ -916,10 +1064,13 @@ mpls_get_fec_by_destination(struct mpls_fec_map *m, ea_list *dest)
   if (fec)
   {
     ea_free(rta->l);
+    mpls_revive_fec(fec);
     return fec;
   }
 
-  u32 label = mpls_new_label(m->domain, m->handle, 0);
+  u32 label = 0;
+  MPLS_HANDLE_LOCKED(m->handle, h)
+    label = mpls_new_label(h, 0);
 
   if (!label)
   {
@@ -927,19 +1078,17 @@ mpls_get_fec_by_destination(struct mpls_fec_map *m, ea_list *dest)
     return NULL;
   }
 
-  fec = sl_allocz(mpls_slab(m, 0));
+  fec = mpls_new_fec(m, 0, label);
 
   fec->hash = hash;
   fec->rta = rta;
 
-  fec->label = label;
   fec->policy = MPLS_POLICY_AGGREGATE;
   fec->handle = m->handle;
 
-  DBG("New FEC rta %u\n", fec->label);
+  DBGL("New FEC rta %u", fec->label);
 
   HASH_INSERT2(m->attrs_hash, RTA, m->pool, fec);
-  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
 
   return fec;
 }
@@ -950,24 +1099,27 @@ mpls_get_fec_for_vrf(struct mpls_fec_map *m)
   struct mpls_fec *fec = m->vrf_fec;
 
   if (fec)
+  {
+    mpls_revive_fec(fec);
     return fec;
+  }
 
-  u32 label = mpls_new_label(m->domain, m->handle, 0);
+  u32 label = 0;
+  MPLS_HANDLE_LOCKED(m->handle, h)
+    label = mpls_new_label(h, 0);
 
   if (!label)
     return NULL;
 
-  fec = sl_allocz(mpls_slab(m, 0));
+  fec = mpls_new_fec(m, 0, label);
 
-  fec->label = label;
   fec->policy = MPLS_POLICY_VRF;
   fec->handle = m->handle;
   fec->iface = m->vrf_iface;
 
-  DBG("New FEC vrf %u\n", fec->label);
+  DBGL("New FEC vrf %u", fec->label);
 
   m->vrf_fec = fec;
-  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
 
   return fec;
 }
@@ -1000,18 +1152,23 @@ mpls_unlink_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
   }
 }
 
-void
+static void
 mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
 {
   if (fec->state != MPLS_FEC_DOWN)
     mpls_withdraw_fec(m, fec);
 
-  DBG("Free FEC %u\n", fec->label);
+  DBGL("Free FEC %p %u of map %p, handle %p", fec, fec->label, m, fec->handle);
 
-  mpls_free_label(m->domain, fec->handle, fec->label);
+  MPLS_DOMAIN_LOCKED(m->domain, domain)
+  {
+    struct mpls_handle *h = MPLS_HANDLE_PRIV(fec->handle);
+    mpls_free_label(h, fec->label);
 
-  if (!fec->policy && !fec->handle->label_count)
-      mpls_free_handle(m->domain, fec->handle);
+    DBGL("Handle %p policy %d label count %d", fec->handle, fec->policy, h->label_count);
+    if (!fec->policy && !h->label_count)
+      mpls_free_handle(h);
+  }
 
   HASH_REMOVE2(m->label_hash, LABEL, m->pool, fec);
 
@@ -1020,50 +1177,22 @@ mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
   sl_free(fec);
 }
 
-static inline void mpls_lock_fec(struct mpls_fec_map *x UNUSED, struct mpls_fec *fec)
-{ if (fec) fec->uc++; }
-
-static inline void mpls_unlock_fec(struct mpls_fec_map *x, struct mpls_fec *fec)
-{ if (fec && !--fec->uc) mpls_free_fec(x, fec); }
-
-struct mpls_fec_tmp_lock {
-  resource r;
-  struct mpls_fec_map *m;
-  struct mpls_fec *fec;
-};
-
-static void
-mpls_fec_tmp_lock_free(resource *r)
+inline void mpls_revive_fec(struct mpls_fec *fec)
 {
-  struct mpls_fec_tmp_lock *l = SKIP_BACK(struct mpls_fec_tmp_lock, r, r);
-  mpls_unlock_fec(l->m, l->fec);
+  UNUSED u64 s = lfuc_lock_revive(&fec->uc);
+  DBGL("Locked FEC %p %u, was %lu (i)", fec, fec->label, s);
 }
 
-static void
-mpls_fec_tmp_lock_dump(resource *r, unsigned indent UNUSED)
+inline void mpls_lock_fec(struct mpls_fec *fec)
 {
-  struct mpls_fec_tmp_lock *l = SKIP_BACK(struct mpls_fec_tmp_lock, r, r);
-  debug("map=%p fec=%p label=%u", l->m, l->fec, l->fec->label);
+  UNUSED u64 s = lfuc_lock(&fec->uc);
+  DBGL("Locked FEC %p %u, was %lu", fec, fec->label, s);
 }
 
-static struct resclass mpls_fec_tmp_lock_class = {
-  .name = "Temporary MPLS FEC Lock",
-  .size = sizeof(struct mpls_fec_tmp_lock),
-  .free = mpls_fec_tmp_lock_free,
-  .dump = mpls_fec_tmp_lock_dump,
-};
-
-static void
-mpls_lock_fec_tmp(struct mpls_fec_map *m, struct mpls_fec *fec)
+inline void mpls_unlock_fec(struct mpls_fec *fec)
 {
-  if (!fec)
-    return;
-
-  fec->uc++;
-
-  struct mpls_fec_tmp_lock *l = ralloc(tmp_res.pool, &mpls_fec_tmp_lock_class);
-  l->m = m;
-  l->fec = fec;
+  UNUSED u64 s = lfuc_unlock(&fec->uc, birdloop_event_list(fec->map->loop), fec->map->cleanup_event);
+  DBGL("Unlocked FEC %p %u, now %lu", fec, fec->label, s);
 }
 
 static inline void
@@ -1114,6 +1243,13 @@ mpls_announce_fec(struct mpls_fec_map *m, struct mpls_fec *fec, ea_list *src)
     ea_set_hostentry(&e.attrs, m->channel->table, he->owner, he->addr, he->link,
        HOSTENTRY_LABEL_COUNT(head), head->labels);
   }
+  else
+  {
+    const struct eattr *nhea = ea_find_by_class(src, &ea_gen_nexthop);
+    if (!nhea)
+      bug("FEC has neither a hostentry, nor a nexthop");
+    ea_set_attr(&e.attrs, *nhea);
+  }
 
   net_addr_mpls n = NET_ADDR_MPLS(fec->label);
 
@@ -1124,6 +1260,10 @@ mpls_announce_fec(struct mpls_fec_map *m, struct mpls_fec *fec, ea_list *src)
 static void
 mpls_withdraw_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
 {
+  /* The MPLS channel is already stopping */
+  if (m->channel->channel_state != CS_UP)
+    return;
+
   net_addr_mpls n = NET_ADDR_MPLS(fec->label);
 
   fec->state = MPLS_FEC_DOWN;
@@ -1150,11 +1290,11 @@ mpls_apply_fec(rte *r, struct mpls_fec *fec)
 
 
 int
-mpls_handle_rte(struct channel *c, const net_addr *n, rte *r)
+mpls_handle_rte(struct channel *c, const net_addr *n, rte *r, struct mpls_fec **fecp)
 {
   struct mpls_channel *mc = SKIP_BACK(struct mpls_channel, c, c->proto->mpls_channel);
   struct mpls_fec_map *m = mc->mpls_map;
-  struct mpls_fec *fec = NULL;
+  struct mpls_fec *fec = *fecp = NULL;
 
   /* Select FEC for route */
   uint policy = ea_get_int(r->attrs, &ea_gen_mpls_policy, 0);
@@ -1205,13 +1345,10 @@ mpls_handle_rte(struct channel *c, const net_addr *n, rte *r)
   if (!fec)
   {
     log(L_WARN "Label allocation in range %s failed for %N from %s",
-       m->handle->range->name, n, r->sender->req->name);
+       m->handle->name, n, r->sender->req->name);
     return -1;
   }
 
-  /* Temporarily lock FEC */
-  mpls_lock_fec_tmp(m, fec);
-
   /* Apply FEC label to route */
   mpls_apply_fec(r, fec);
 
@@ -1219,52 +1356,52 @@ mpls_handle_rte(struct channel *c, const net_addr *n, rte *r)
   if (fec->state != MPLS_FEC_CLEAN)
     mpls_announce_fec(m, fec, r->attrs);
 
+  /* Store the returned FEC for later unlock */
+  *fecp = fec;
   return 0;
 }
 
-static inline struct mpls_fec_tmp_lock
-mpls_rte_get_fec_lock(const rte *r)
+static inline struct mpls_fec *
+mpls_rte_get_fec(const rte *r)
 {
-  struct mpls_fec_tmp_lock mt = {};
-
   struct channel *c = SKIP_BACK(struct proto, sources, r->src->owner)->mpls_channel;
   if (!c)
-    return mt;
+    return NULL;
 
-  mt.m = SKIP_BACK(struct mpls_channel, c, c)->mpls_map;
   uint label = ea_get_int(r->attrs, &ea_gen_mpls_label, 0);
   if (label < 16)
-    return mt;
+    return NULL;
 
-  mt.fec = mpls_find_fec_by_label(mt.m, label);
-  return mt;
+  return mpls_find_fec_by_label(SKIP_BACK(struct mpls_channel, c, c)->mpls_map, label);
 }
 
 void
 mpls_rte_preimport(rte *new, const rte *old)
 {
-  struct mpls_fec_tmp_lock new_mt = {}, old_mt = {};
-
-  if (new)
-    new_mt = mpls_rte_get_fec_lock(new);
+  struct mpls_fec *new_fec = new ? mpls_rte_get_fec(new) : NULL;
+  struct mpls_fec *old_fec = old ? mpls_rte_get_fec(old) : NULL;
 
-  if (old)
-    old_mt = mpls_rte_get_fec_lock(old);
 
-  if (new_mt.fec == old_mt.fec)
+  if (new_fec == old_fec)
     return;
 
-  if (new_mt.fec)
-    mpls_lock_fec(new_mt.m, new_mt.fec);
+  if (new_fec)
+  {
+    DBGL("Lock FEC %p (preimport %p)", new_fec, new);
+    mpls_lock_fec(new_fec);
+  }
 
-  if (old_mt.fec)
-    mpls_unlock_fec(old_mt.m, old_mt.fec);
+  if (old_fec)
+  {
+    mpls_unlock_fec(old_fec);
+    DBGL("Unlock FEC %p (preimport %p)", old_fec, old);
+  }
 }
 
 static void
-mpls_show_ranges_rng(struct mpls_show_ranges_cmd *cmd, struct mpls_range *r)
+mpls_show_ranges_rng(struct mpls_show_ranges_cmd *cmd UNUSED, struct mpls_range *r)
 {
-  uint last = lmap_last_one_in_range(&cmd->dom->labels, r->lo, r->hi);
+  uint last = lmap_last_one_in_range(&r->domain->labels, r->lo, r->hi);
   if (last == r->hi) last = 0;
 
   cli_msg(-1026, "%-11s %7u %7u %7u %7u %7u",
@@ -1272,18 +1409,16 @@ mpls_show_ranges_rng(struct mpls_show_ranges_cmd *cmd, struct mpls_range *r)
 }
 
 void
-mpls_show_ranges_dom(struct mpls_show_ranges_cmd *cmd, struct mpls_domain *m)
+mpls_show_ranges_dom(struct mpls_show_ranges_cmd *cmd, struct mpls_domain_pub *mpub)
 {
-  if (cmd->dom)
-    cli_msg(-1026, "");
+  MPLS_DOMAIN_LOCK(mpub, m);
 
-  cmd->dom = m;
   cli_msg(-1026, "MPLS domain %s:", m->name);
   cli_msg(-1026, "%-11s %7s %7s %7s %7s %7s",
          "Range", "Start", "Length", "End", "Labels", "Last");
 
   if (cmd->range)
-    mpls_show_ranges_rng(cmd, cmd->range->range);
+    mpls_show_ranges_rng(cmd, MPLS_RANGE_PRIV(cmd->range->range));
   else
   {
     struct mpls_range *r;
@@ -1300,9 +1435,17 @@ mpls_show_ranges(struct mpls_show_ranges_cmd *cmd)
     mpls_show_ranges_dom(cmd, cmd->domain->domain);
   else
   {
-    struct mpls_domain *m;
+    struct mpls_domain_pub *m;
+    _Bool first = 1;
     WALK_LIST(m, MPLS_GLOBAL->domains)
+    {
+      if (first)
+       first = 0;
+      else
+       cli_msg(-1026, "");
+
       mpls_show_ranges_dom(cmd, m);
+    }
   }
 
   cli_msg(0, "");
index f6734001572b60efe0a059cb2fb710ceba026c03..79c3a6e3ec30a55713874eec2f1100697d8b93aa 100644 (file)
@@ -30,7 +30,7 @@
 
 struct mpls_domain_config {
   node n;                              /* Node in config.mpls_domains */
-  struct mpls_domain *domain;          /* Our instance */
+  struct mpls_domain_pub *domain;      /* Our instance */
   const char *name;
 
   list ranges;                         /* List of label ranges (struct mpls_range_config) */
@@ -40,7 +40,7 @@ struct mpls_domain_config {
 
 struct mpls_range_config {
   node n;                              /* Node in mpls_domain_config.ranges */
-  struct mpls_range *range;            /* Our instance */
+  struct mpls_range_pub *range;                /* Our instance */
   struct mpls_domain_config *domain;   /* Parent MPLS domain */
   const char *name;
 
@@ -49,9 +49,6 @@ struct mpls_range_config {
   u8 implicit;                         /* Implicitly defined range */
 };
 
-struct mpls_handle;
-
-
 void mpls_init(void);
 struct mpls_domain_config * mpls_domain_config_new(struct symbol *s);
 void mpls_domain_postconfig(struct mpls_domain_config *cf);
@@ -76,8 +73,8 @@ struct mpls_channel_config {
 struct mpls_channel {
   struct channel c;
 
-  struct mpls_domain *domain;
-  struct mpls_range *range;
+  struct mpls_domain_pub *domain;
+  struct mpls_range_pub *range;
 
   uint label_policy;
   uint rts;
@@ -103,7 +100,6 @@ proto_configure_mpls_channel(struct proto *p, struct proto_config *pc, uint rts)
 struct mpls_fec {
   u32 label;                           /* Label for FEC */
   u32 hash;                            /* Hash for primary key (net / rta) */
-  u32 uc;                              /* Number of LSPs for FEC */
   union {                              /* Extension part of key */
     u32 path_id;                       /* Source path_id */
   };
@@ -111,7 +107,10 @@ struct mpls_fec {
   u8 state;                            /* FEC state (MPLS_FEC_*) */
   u8 policy;                           /* Label policy (MPLS_POLICY_*) */
 
-  struct mpls_handle *handle;          /* Handle holding the label */
+  struct lfuc uc;                      /* Number of LSPs for FEC */
+
+  struct mpls_handle_pub *handle;      /* Handle holding the label */
+  struct mpls_fec_map *map;            /* Belonging to this map */
 
   struct mpls_fec *next_k;             /* Next in mpls_fec.net_hash/rta_hash */
   struct mpls_fec *next_l;             /* Next in mpls_fec.label_hash */
@@ -124,6 +123,8 @@ struct mpls_fec {
 
 struct mpls_fec_map {
   pool *pool;                          /* Pool for FEC map */
+  struct birdloop *loop;               /* Owner's loop for sending events */
+  event *cleanup_event;                        /* Event for unlocked FEC cleanup */
   slab *slabs[4];                      /* Slabs for FEC allocation */
   HASH(struct mpls_fec) net_hash;      /* Hash table for MPLS_POLICY_PREFIX FECs */
   HASH(struct mpls_fec) attrs_hash;    /* Hash table for MPLS_POLICY_AGGREGATE FECs */
@@ -131,33 +132,33 @@ struct mpls_fec_map {
   struct mpls_fec *vrf_fec;            /* Single FEC for MPLS_POLICY_VRF */
 
   struct channel *channel;             /* MPLS channel for FEC announcement */
-  struct mpls_domain *domain;          /* MPLS domain, keeping reference */
-  struct mpls_handle *handle;          /* Handle for dynamic allocation of labels */
-  struct mpls_handle *static_handle;   /* Handle for static label allocations, optional */
+  struct mpls_domain_pub *domain;      /* MPLS domain, keeping reference */
+  struct mpls_handle_pub *handle;      /* Handle for dynamic allocation of labels */
+  struct mpls_handle_pub *static_handle;/* Handle for static label allocations, optional */
   struct iface *vrf_iface;
 
   u8 mpls_rts;                         /* Source value used for MPLS routes (RTS_*) */
 };
 
 
-struct mpls_fec_map *mpls_fec_map_new(pool *p, struct channel *c, uint rts);
+struct mpls_fec_map *mpls_fec_map_new(pool *p, struct birdloop *loop, struct channel *c, uint rts);
 void mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C);
 void mpls_fec_map_free(struct mpls_fec_map *m);
 struct mpls_fec *mpls_find_fec_by_label(struct mpls_fec_map *x, u32 label);
 struct mpls_fec *mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label);
 struct mpls_fec *mpls_get_fec_by_net(struct mpls_fec_map *m, const net_addr *net, u32 path_id);
 struct mpls_fec *mpls_get_fec_by_destination(struct mpls_fec_map *m, ea_list *dest);
-void mpls_free_fec(struct mpls_fec_map *x, struct mpls_fec *fec);
-int mpls_handle_rte(struct channel *c, const net_addr *n, rte *r);
+
+void mpls_lock_fec(struct mpls_fec *fec);
+void mpls_unlock_fec(struct mpls_fec *fec);
+
+int mpls_handle_rte(struct channel *c, const net_addr *n, rte *r, struct mpls_fec **fecp);
 void mpls_rte_preimport(rte *new, const rte *old);
 
 
 struct mpls_show_ranges_cmd {
   struct mpls_domain_config *domain;
   struct mpls_range_config *range;
-
-  /* Runtime */
-  struct mpls_domain *dom;
 };
 
 void mpls_show_ranges(struct mpls_show_ranges_cmd *cmd);
index 29ee8bd38a9d7a45e6db586bfe873af6beb454fb..84454831261a986c0e25d2e57d10e8fbe650abb7 100644 (file)
@@ -1769,6 +1769,7 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 
   const struct filter *filter = c->in_filter;
   struct channel_import_stats *stats = &c->import_stats;
+  struct mpls_fec *fec = NULL;
 
   if (new)
     {
@@ -1790,7 +1791,7 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
        }
 
       if (new && c->proto->mpls_channel)
-       if (mpls_handle_rte(c->proto->mpls_channel, n, new) < 0)
+       if (mpls_handle_rte(c->proto->mpls_channel, n, new, &fec) < 0)
          {
            channel_rte_trace_in(D_FILTERS, c, new, "invalid");
            stats->updates_invalid++;
@@ -1815,6 +1816,12 @@ rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 
   rte_import(&c->in_req, n, new, src);
 
+  if (fec)
+  {
+    mpls_unlock_fec(fec);
+    DBGL( "Unlock FEC %p (rte_update %N)", fec, n);
+  }
+
   /* Now the route attributes are kept by the in-table cached version
    * and we may drop the local handle */
   if (new && (c->in_keep & RIK_PREFILTER))
index c888460a0568c22781bcdfab12b5803a009e339f..1bce53decbdbd013601337eefb31a1f9af2ebbd0 100644 (file)
@@ -628,7 +628,7 @@ bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len)
   bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
 
   struct bgp_channel *c;
-  WALK_LIST(c, p->p.channels)
+  BGP_WALK_CHANNELS(p, c)
     if (c->ptx)
       bgp_free_pending_tx(c);