]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
MPLS: Improve handling of static label allocations
authorOndrej Zajicek <santiago@crfreenet.org>
Sat, 23 Sep 2023 15:55:01 +0000 (17:55 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 4 Oct 2023 11:12:05 +0000 (13:12 +0200)
Use mpls_new_label() / mpls_free_label() also for static labels, to keep
track of allocated labels and to enforce label ranges.

Static label allocations always use static label range, regardless of
configured label range.

nest/mpls.c
nest/mpls.h

index 03180913b7e06622aa16e4e7a36bf24dfc078587..c9ae78f8a58980eb3c4bcd1fa75c1454cab4e965 100644 (file)
@@ -78,8 +78,7 @@
  * TODO:
  *  - protocols should do route refresh instead of restart when reconfiguration
  *    requires changing labels (e.g. different label range)
- *  - registering static allocations
- *  - checking range in static allocations
+ *  - handle label allocation failures
  *  - special handling of reserved labels
  */
 
@@ -481,12 +480,14 @@ mpls_free_handle(struct mpls_domain *m UNUSED, struct mpls_handle *h)
  */
 
 uint
-mpls_new_label(struct mpls_domain *m, struct mpls_handle *h)
+mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
 {
   struct mpls_range *r = h->range;
-  uint n = lmap_first_zero_in_range(&m->labels, r->lo, r->hi);
 
-  if (n >= r->hi)
+  if (!n)
+    n = lmap_first_zero_in_range(&m->labels, r->lo, r->hi);
+
+  if ((n < r->lo) || (n >= r->hi) || lmap_test(&m->labels, n))
     return 0;
 
   m->label_count++;
@@ -583,8 +584,7 @@ mpls_channel_postconfig(struct channel_config *CC)
     cf_error("MPLS domain not specified");
 
   if (!cc->range)
-    cc->range = (cc->label_policy == MPLS_POLICY_STATIC) ?
-      cc->domain->static_range : cc->domain->dynamic_range;
+    cc->range = cc->domain->dynamic_range;
 
   if (cc->range->domain != cc->domain)
     cf_error("MPLS label range from different MPLS domain");
@@ -684,11 +684,14 @@ mpls_fec_map_free(struct mpls_fec_map *m)
   /* Free allocated labels */
   HASH_WALK(m->label_hash, next_l, fec)
   {
-    if (fec->policy != MPLS_POLICY_STATIC)
-      mpls_free_label(m->domain, m->handle, fec->label);
+    struct mpls_handle *h = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
+    mpls_free_label(m->domain, h, fec->label);
   }
   HASH_WALK_END;
 
+  if (m->static_handle)
+    mpls_free_handle(m->domain, m->static_handle);
+
   mpls_free_handle(m->domain, m->handle);
   mpls_unlock_domain(m->domain);
 
@@ -717,13 +720,17 @@ 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);
+  /* FIXME: check if (fec->policy == MPLS_POLICY_STATIC) */
 
   if (fec)
     return fec;
 
   fec = sl_allocz(mpls_slab(m, 0));
 
-  fec->label = label;
+  if (!m->static_handle)
+    m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
+
+  fec->label = mpls_new_label(m->domain, m->static_handle, label);
   fec->policy = MPLS_POLICY_STATIC;
 
   DBG("New FEC lab %u\n", fec->label);
@@ -751,7 +758,7 @@ mpls_get_fec_by_net(struct mpls_fec_map *m, const net_addr *net, u32 path_id)
   fec->path_id = path_id;
   net_copy(fec->net, net);
 
-  fec->label = mpls_new_label(m->domain, m->handle);
+  fec->label = mpls_new_label(m->domain, m->handle, 0);
   fec->policy = MPLS_POLICY_PREFIX;
 
   DBG("New FEC net %u\n", fec->label);
@@ -784,7 +791,7 @@ mpls_get_fec_by_rta(struct mpls_fec_map *m, const rta *src, u32 class_id)
   fec->class_id = class_id;
   fec->rta = rta;
 
-  fec->label = mpls_new_label(m->domain, m->handle);
+  fec->label = mpls_new_label(m->domain, m->handle, 0);
   fec->policy = MPLS_POLICY_AGGREGATE;
 
   DBG("New FEC rta %u\n", fec->label);
@@ -805,7 +812,7 @@ mpls_get_fec_for_vrf(struct mpls_fec_map *m)
 
   fec = sl_allocz(mpls_slab(m, 0));
 
-  fec->label = mpls_new_label(m->domain, m->handle);
+  fec->label = mpls_new_label(m->domain, m->handle, 0);
   fec->policy = MPLS_POLICY_VRF;
   fec->iface = m->vrf_iface;
 
@@ -825,8 +832,8 @@ mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
 
   DBG("Free FEC %u\n", fec->label);
 
-  if (fec->policy != MPLS_POLICY_STATIC)
-    mpls_free_label(m->domain, m->handle, fec->label);
+  struct mpls_handle *h = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
+  mpls_free_label(m->domain, h, fec->label);
 
   HASH_REMOVE2(m->label_hash, LABEL, m->pool, fec);
 
index 6452220a64c2e7a72da31345ef51038ff1adf367..52865f1ce40012be02c5e1676d596e534f17d29d 100644 (file)
@@ -91,7 +91,7 @@ void mpls_domain_postconfig(struct mpls_domain_config *cf);
 struct mpls_range_config * mpls_range_config_new(struct mpls_domain_config *m, struct symbol *s);
 void mpls_preconfig(struct config *c);
 void mpls_commit(struct config *new, struct config *old);
-uint mpls_new_label(struct mpls_domain *m, struct mpls_handle *h);
+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);
 
 static inline struct mpls_domain_config *cf_default_mpls_domain(struct config *cfg)
@@ -153,6 +153,7 @@ struct mpls_fec_map {
   struct channel *channel;             /* MPLS channel for FEC announcement */
   struct mpls_domain *domain;          /* MPLS domain, keeping reference */
   struct mpls_handle *handle;          /* Handle for allocation of labels */
+  struct mpls_handle *static_handle;   /* Handle for static label allocations, optional */
   struct iface *vrf_iface;
 
   u8 mpls_rts;                         /* Source value used for MPLS routes (RTS_*) */