aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2022-10-01 22:38:49 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2023-10-04 13:01:21 +0200
commit9ca86ef69cc56cb75e48e6f46bfdbe1b1e3e99b6 (patch)
tree849b550390cb1b8ce654e764d539396734b8c4dd
parent9d456d5366593c7b0ebfde003be0517adb554541 (diff)
downloadbird-9ca86ef69cc56cb75e48e6f46bfdbe1b1e3e99b6.tar.gz
MPLS: Add support for per-VRF labeling policy
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.
-rw-r--r--nest/config.Y2
-rw-r--r--nest/mpls.Y3
-rw-r--r--nest/mpls.c48
-rw-r--r--nest/mpls.h6
4 files changed, 53 insertions, 6 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 31b9bd44..6869137b 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -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
diff --git a/nest/mpls.Y b/nest/mpls.Y
index b4ae990b..5c46392c 100644
--- a/nest/mpls.Y
+++ b/nest/mpls.Y
@@ -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:
diff --git a/nest/mpls.c b/nest/mpls.c
index cd3a90d9..df03a86b 100644
--- a/nest/mpls.c
+++ b/nest/mpls.c
@@ -52,14 +52,16 @@
* 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;
diff --git a/nest/mpls.h b/nest/mpls.h
index a84ede14..4b071ad8 100644
--- a/nest/mpls.h
+++ b/nest/mpls.h
@@ -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_*) */
};