]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
MPLS: Add support for per-VRF labeling policy
authorOndrej Zajicek <santiago@crfreenet.org>
Sat, 1 Oct 2022 20:38:49 +0000 (22:38 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 4 Oct 2023 11:01:21 +0000 (13:01 +0200)
The new labeling policy MPLS_POLICY_VRF assigns one label to all routes
(from the same FEC map associated with one VRF), while replaces their
next hops with a lookup to a VRF table. This is useful for L3VPN
protocol.

nest/config.Y
nest/mpls.Y
nest/mpls.c
nest/mpls.h

index 31b9bd44f18da5306c62da8cd4fead371130ed55..6869137bac493c0891ac00c9dfeb5a8750141bae 100644 (file)
@@ -138,7 +138,7 @@ CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINE
 CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
 CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
 CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
-CF_ENUM(T_ENUM_MPLS_POLICY, MPLS_POLICY_, NONE, STATIC, PREFIX, AGGREGATE)
+CF_ENUM(T_ENUM_MPLS_POLICY, MPLS_POLICY_, NONE, STATIC, PREFIX, AGGREGATE, VRF)
 
 %type <i32> idval
 %type <f> imexport
index b4ae990b46c4ba1f8a80f37547abd717793dabbb..5c46392c078e61639d82e2ff312e63099424ed5d 100644 (file)
@@ -20,7 +20,7 @@ static struct mpls_range_config *this_mpls_range;
 
 CF_DECLS
 
-CF_KEYWORDS(MPLS, DOMAIN, LABEL, RANGE, STATIC, DYNAMIC, START, LENGTH, POLICY, PREFIX, AGGREGATE)
+CF_KEYWORDS(MPLS, DOMAIN, LABEL, RANGE, STATIC, DYNAMIC, START, LENGTH, POLICY, PREFIX, AGGREGATE, VRF)
 
 %type <i> mpls_label_policy
 %type <cc> mpls_channel_start mpls_channel
@@ -112,6 +112,7 @@ mpls_label_policy:
    STATIC { $$ = MPLS_POLICY_STATIC; }
  | PREFIX { $$ = MPLS_POLICY_PREFIX; }
  | AGGREGATE { $$ = MPLS_POLICY_AGGREGATE; }
+ | VRF { $$ = MPLS_POLICY_VRF; }
  ;
 
 mpls_channel_opt:
index cd3a90d97c155748cac7af14e7185dc6e7f2c908..df03a86b18549be3776f3697a8f3fcf6a6e319ce 100644 (file)
  * map, which can be used by the protocols that work with IP-prefix-based FECs.
  *
  * The FEC map keeps hash tables of FECs (struct &mpls_fec) based on network
- * prefix, next hop eattr and assigned label. It has three labeling policies:
+ * prefix, next hop eattr and assigned label. It has three general labeling policies:
  * static assignment (%MPLS_POLICY_STATIC), per-prefix policy (%MPLS_POLICY_PREFIX),
  * and aggregating policy (%MPLS_POLICY_AGGREGATE). In per-prefix policy, each
  * distinct LSP is a separate FEC and uses a separate label, which is kept even
  * if the next hop of the LSP changes. In aggregating policy, LSPs with a same
  * next hop form one FEC and use one label, but when a next hop (or remote
  * label) of such LSP changes then the LSP must be moved to a different FEC and
- * assigned a different label.
+ * assigned a different label. There is also a special VRF policy (%MPLS_POLICY_VRF)
+ * applicable for L3VPN protocols, which uses one label for all routes from a VRF,
+ * while replacing the original next hop with lookup in the VRF.
  *
  * The overall process works this way: A protocol wants to announce a LSP route,
  * it does that by announcing e.g. IP route with %EA_MPLS_POLICY attribute.
@@ -746,6 +748,28 @@ mpls_get_fec_by_rta(struct mpls_fec_map *m, const rta *src, u32 class_id)
   return fec;
 }
 
+struct mpls_fec *
+mpls_get_fec_for_vrf(struct mpls_fec_map *m)
+{
+  struct mpls_fec *fec = m->vrf_fec;
+
+  if (fec)
+    return fec;
+
+  fec = sl_allocz(mpls_slab(m, 0));
+
+  fec->label = mpls_new_label(m->domain, m->handle);
+  fec->policy = MPLS_POLICY_VRF;
+  fec->iface = m->vrf_iface;
+
+  DBG("New FEC vrf %u\n", fec->label);
+
+  m->vrf_fec = fec;
+  HASH_INSERT2(m->label_hash, LABEL, m->pool, fec);
+
+  return fec;
+}
+
 void
 mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
 {
@@ -771,6 +795,11 @@ mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
     HASH_REMOVE2(m->rta_hash, RTA, m->pool, fec);
     break;
 
+  case MPLS_POLICY_VRF:
+    ASSERT(m->vrf_fec == fec);
+    m->vrf_fec = NULL;
+    break;
+
   default:
     bug("Unknown fec type");
   }
@@ -892,6 +921,13 @@ mpls_apply_fec(rte *r, struct mpls_fec *fec, linpool *lp)
 
   r->attrs->eattrs = ea;
 
+  if (fec->policy == MPLS_POLICY_VRF)
+  {
+    r->attrs->hostentry = NULL;
+    r->attrs->dest = RTD_UNICAST;
+    r->attrs->nh = (struct nexthop) { .iface = fec->iface };
+  }
+
   if (rta_is_cached(old_attrs))
   {
     r->attrs = rta_lookup(r->attrs);
@@ -907,7 +943,6 @@ mpls_handle_rte(struct mpls_fec_map *m, const net_addr *n, rte *r, linpool *lp,
 
   struct mpls_fec *fec = NULL;
 
-
   /* Select FEC for route */
   uint policy = ea_get_int(r->attrs->eattrs, EA_MPLS_POLICY, 0);
   switch (policy)
@@ -935,6 +970,13 @@ mpls_handle_rte(struct mpls_fec_map *m, const net_addr *n, rte *r, linpool *lp,
     fec = mpls_get_fec_by_rta(m, r->attrs, class);
     break;
 
+  case MPLS_POLICY_VRF:
+    if (!m->vrf_iface)
+      return;
+
+    fec = mpls_get_fec_for_vrf(m);
+    break;
+
   default:
     log(L_WARN "Route %N has invalid MPLS policy %u", n, policy);
     return;
index a84ede14adf5a38243582bf2cef8d4a4b051ab85..4b071ad8bff14ad885a5c7af394202a24673f1a9 100644 (file)
@@ -21,6 +21,7 @@
 #define MPLS_POLICY_STATIC     1
 #define MPLS_POLICY_PREFIX     2
 #define MPLS_POLICY_AGGREGATE  3
+#define MPLS_POLICY_VRF                4
 
 #define MPLS_FEC_DOWN          0
 #define MPLS_FEC_CLEAN         1
@@ -135,6 +136,7 @@ struct mpls_fec {
   struct mpls_fec *next_l;             /* Next in mpls_fec.label_hash */
   union {                              /* Primary key */
     struct rta *rta;
+    struct iface *iface;
     net_addr net[0];
   };
 };
@@ -145,13 +147,15 @@ struct mpls_fec_map {
   HASH(struct mpls_fec) net_hash;      /* Hash table for MPLS_POLICY_PREFIX FECs */
   HASH(struct mpls_fec) rta_hash;      /* Hash table for MPLS_POLICY_AGGREGATE FECs */
   HASH(struct mpls_fec) label_hash;    /* Hash table for FEC lookup by label */
+  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 allocation of labels */
+  struct iface *vrf_iface;
 
   u8 mpls_rts;                         /* Source value used for MPLS routes (RTS_*) */
-  u8 mpls_scope;                       /* Scope  value used for MPLS routes () */
+  u8 mpls_scope;                       /* Scope  value used for MPLS routes (SCOPE_*) */
 };