2 * BIRD Internet Routing Daemon -- MPLS Structures
4 * (c) 2022 Ondrej Zajicek <santiago@crfreenet.org>
5 * (c) 2022 CZ.NIC z.s.p.o.
7 * Can be freely distributed and used under the terms of the GNU GPL.
13 * The MPLS subsystem manages MPLS labels and handles their allocation to
14 * MPLS-aware routing protocols. These labels are then attached to IP or VPN
15 * routes representing label switched paths -- LSPs. MPLS labels are also used
16 * in special MPLS routes (which use labels as network address) that are
17 * exported to MPLS routing table in kernel. The MPLS subsystem consists of MPLS
18 * domains (struct &mpls_domain), MPLS channels (struct &mpls_channel) and FEC
19 * maps (struct &mpls_fec_map).
21 * The MPLS domain represents one MPLS label address space, implements the label
22 * allocator, and handles associated configuration and management. The domain is
23 * declared in the configuration (struct &mpls_domain_config). There might be
24 * multiple MPLS domains representing separate label spaces, but in most cases
25 * one domain is enough. MPLS-aware protocols and routing tables are associated
26 * with a specific MPLS domain.
28 * The MPLS domain has configurable label ranges (struct &mpls_range), by
29 * default it has two ranges: static (16-1000) and dynamic (1000-10000). When
30 * a protocol wants to allocate labels, it first acquires a handle (struct
31 * &mpls_handle) for a specific range using mpls_new_handle(), and then it
32 * allocates labels from that with mpls_new_label(). When not needed, labels are
33 * freed by mpls_free_label() and the handle is released by mpls_free_handle().
34 * Note that all labels and handles must be freed manually.
36 * Both MPLS domain and MPLS range are reference counted, so when deconfigured
37 * they could be freed just after all labels and ranges are freed. Users are
38 * expected to hold a reference to a MPLS domain for whole time they use
39 * something from that domain (e.g. &mpls_handle), but releasing reference to
40 * a range while holding associated handle is OK.
42 * The MPLS channel is subclass of a generic protocol channel. It has two
43 * distinct purposes - to handle per-protocol MPLS configuration (e.g. which
44 * MPLS domain is associated with the protocol, which label range is used by the
45 * protocol), and to announce MPLS routes to a routing table (as a regular
48 * The FEC map is a helper structure that maps forwarding equivalent classes
49 * (FECs) to MPLS labels. It is an internal matter of a routing protocol how to
50 * assign meaning to allocated labels, announce LSP routes and associated MPLS
51 * routes (i.e. ILM entries). But the common behavior is implemented in the FEC
52 * map, which can be used by the protocols that work with IP-prefix-based FECs.
54 * The FEC map keeps hash tables of FECs (struct &mpls_fec) based on network
55 * prefix, next hop eattr and assigned label. It has three general labeling policies:
56 * static assignment (%MPLS_POLICY_STATIC), per-prefix policy (%MPLS_POLICY_PREFIX),
57 * and aggregating policy (%MPLS_POLICY_AGGREGATE). In per-prefix policy, each
58 * distinct LSP is a separate FEC and uses a separate label, which is kept even
59 * if the next hop of the LSP changes. In aggregating policy, LSPs with a same
60 * next hop form one FEC and use one label, but when a next hop (or remote
61 * label) of such LSP changes then the LSP must be moved to a different FEC and
62 * assigned a different label. There is also a special VRF policy (%MPLS_POLICY_VRF)
63 * applicable for L3VPN protocols, which uses one label for all routes from a VRF,
64 * while replacing the original next hop with lookup in the VRF.
66 * The overall process works this way: A protocol wants to announce a LSP route,
67 * it does that by announcing e.g. IP route with %EA_MPLS_POLICY attribute.
68 * After the route is accepted by filters (which may also change the policy
69 * attribute or set a static label), the mpls_handle_rte() is called from
70 * rte_update2(), which applies selected labeling policy, finds existing FEC or
71 * creates a new FEC (which includes allocating new label and announcing related
72 * MPLS route by mpls_announce_fec()), and attach FEC label to the LSP route.
73 * After that, the LSP route is stored in routing table by rte_recalculate().
74 * Changes in routing tables trigger mpls_rte_insert() and mpls_rte_remove()
75 * hooks, which refcount FEC structures and possibly trigger removal of FECs
76 * and withdrawal of MPLS routes.
79 * - special handling of reserved labels
84 #include "nest/bird.h"
85 #include "nest/route.h"
86 #include "nest/mpls.h"
89 static struct mpls_range
*mpls_new_range(struct mpls_domain
*m
, struct mpls_range_config
*cf
);
90 static struct mpls_range
*mpls_find_range_(list
*l
, const char *name
);
91 static int mpls_reconfigure_range(struct mpls_domain
*m
, struct mpls_range
*r
, struct mpls_range_config
*cf
);
92 static void mpls_remove_range(struct mpls_range
*r
);
104 init_list(&mpls_domains
);
107 struct mpls_domain_config
*
108 mpls_domain_config_new(struct symbol
*s
)
110 struct mpls_domain_config
*mc
= cfg_allocz(sizeof(struct mpls_domain_config
));
111 struct mpls_range_config
*rc
;
113 cf_define_symbol(new_config
, s
, SYM_MPLS_DOMAIN
, mpls_domain
, mc
);
115 init_list(&mc
->ranges
);
117 /* Predefined static range */
118 rc
= mpls_range_config_new(mc
, NULL
);
123 mc
->static_range
= rc
;
125 /* Predefined dynamic range */
126 rc
= mpls_range_config_new(mc
, NULL
);
127 rc
->name
= "dynamic";
131 mc
->dynamic_range
= rc
;
133 add_tail(&new_config
->mpls_domains
, &mc
->n
);
139 mpls_compare_range_configs(const void *r1_
, const void *r2_
)
141 const struct mpls_range_config
* const *r1
= r1_
;
142 const struct mpls_range_config
* const *r2
= r2_
;
144 return uint_cmp((*r1
)->start
, (*r2
)->start
);
148 mpls_domain_postconfig(struct mpls_domain_config
*cf UNUSED
)
150 /* Label range non-intersection check */
152 int num_ranges
= list_length(&cf
->ranges
);
153 struct mpls_range_config
**ranges
= tmp_alloc(num_ranges
* sizeof(struct mpls_range_config
*));
157 struct mpls_range_config
*r
;
158 WALK_LIST(r
, cf
->ranges
)
162 qsort(ranges
, num_ranges
, sizeof(struct mpls_range_config
*), mpls_compare_range_configs
);
164 struct mpls_range_config
*max_range
= NULL
;
167 for (int i
= 0; i
< num_ranges
; i
++)
169 struct mpls_range_config
*r
= ranges
[i
];
170 uint hi
= r
->start
+ r
->length
;
175 if (r
->start
< max_hi
)
176 cf_warn("MPLS label ranges %s and %s intersect", max_range
->name
, r
->name
);
186 static struct mpls_domain
*
187 mpls_new_domain(struct mpls_domain_config
*cf
)
189 struct pool
*p
= rp_new(&root_pool
, "MPLS domain");
190 struct mpls_domain
*m
= mb_allocz(p
, sizeof(struct mpls_domain
));
196 lmap_init(&m
->labels
, p
);
197 lmap_set(&m
->labels
, 0);
199 init_list(&m
->ranges
);
200 init_list(&m
->handles
);
202 struct mpls_range_config
*rc
;
203 WALK_LIST(rc
, cf
->ranges
)
204 mpls_new_range(m
, rc
);
206 add_tail(&mpls_domains
, &m
->n
);
212 static struct mpls_domain
*
213 mpls_find_domain_(list
*l
, const char *name
)
215 struct mpls_domain
*m
;
218 if (!strcmp(m
->name
, name
))
225 mpls_reconfigure_domain(struct mpls_domain
*m
, struct mpls_domain_config
*cf
)
228 m
->cf
->domain
= NULL
;
232 /* Reconfigure label ranges */
234 init_list(&old_ranges
);
235 add_tail_list(&old_ranges
, &m
->ranges
);
236 init_list(&m
->ranges
);
238 struct mpls_range_config
*rc
;
239 WALK_LIST(rc
, cf
->ranges
)
241 struct mpls_range
*r
= mpls_find_range_(&old_ranges
, rc
->name
);
243 if (r
&& mpls_reconfigure_range(m
, r
, rc
))
246 add_tail(&m
->ranges
, &r
->n
);
250 mpls_new_range(m
, rc
);
253 struct mpls_range
*r
, *r2
;
254 WALK_LIST_DELSAFE(r
, r2
, old_ranges
)
256 mpls_remove_range(r
);
258 add_tail_list(&m
->ranges
, &old_ranges
);
264 mpls_free_domain(struct mpls_domain
*m
)
266 ASSERT(m
->use_count
== 0);
267 ASSERT(m
->label_count
== 0);
268 ASSERT(EMPTY_LIST(m
->handles
));
270 struct config
*cfg
= m
->removed
;
272 m
->cf
->domain
= NULL
;
276 config_del_obstacle(cfg
);
280 mpls_remove_domain(struct mpls_domain
*m
, struct config
*cfg
)
283 config_add_obstacle(cfg
);
290 mpls_lock_domain(struct mpls_domain
*m
)
296 mpls_unlock_domain(struct mpls_domain
*m
)
298 ASSERT(m
->use_count
> 0);
301 if (!m
->use_count
&& m
->removed
)
306 mpls_preconfig(struct config
*c
)
308 init_list(&c
->mpls_domains
);
312 mpls_commit(struct config
*new, struct config
*old
)
315 init_list(&old_domains
);
316 add_tail_list(&old_domains
, &mpls_domains
);
317 init_list(&mpls_domains
);
319 struct mpls_domain_config
*mc
;
320 WALK_LIST(mc
, new->mpls_domains
)
322 struct mpls_domain
*m
= mpls_find_domain_(&old_domains
, mc
->name
);
324 if (m
&& mpls_reconfigure_domain(m
, mc
))
327 add_tail(&mpls_domains
, &m
->n
);
334 struct mpls_domain
*m
, *m2
;
335 WALK_LIST_DELSAFE(m
, m2
, old_domains
)
336 mpls_remove_domain(m
, old
);
338 add_tail_list(&mpls_domains
, &old_domains
);
346 struct mpls_range_config
*
347 mpls_range_config_new(struct mpls_domain_config
*mc
, struct symbol
*s
)
349 struct mpls_range_config
*rc
= cfg_allocz(sizeof(struct mpls_range_config
));
352 cf_define_symbol(new_config
, s
, SYM_MPLS_RANGE
, mpls_range
, rc
);
355 rc
->name
= s
? s
->name
: NULL
;
356 rc
->start
= (uint
) -1;
357 rc
->length
= (uint
) -1;
359 add_tail(&mc
->ranges
, &rc
->n
);
364 static struct mpls_range
*
365 mpls_new_range(struct mpls_domain
*m
, struct mpls_range_config
*cf
)
367 struct mpls_range
*r
= mb_allocz(m
->pool
, sizeof(struct mpls_range
));
372 r
->hi
= cf
->start
+ cf
->length
;
374 add_tail(&m
->ranges
, &r
->n
);
380 static struct mpls_range
*
381 mpls_find_range_(list
*l
, const char *name
)
383 struct mpls_range
*r
;
386 if (!strcmp(r
->name
, name
) && !r
->removed
)
393 mpls_reconfigure_range(struct mpls_domain
*m
, struct mpls_range
*r
, struct mpls_range_config
*cf
)
395 uint last
= lmap_last_one_in_range(&m
->labels
, r
->lo
, r
->hi
);
396 if (last
== r
->hi
) last
= 0;
398 if ((cf
->start
> r
->lo
) || (cf
->start
+ cf
->length
<= last
))
406 r
->hi
= cf
->start
+ cf
->length
;
412 mpls_free_range(struct mpls_range
*r
)
414 ASSERT(r
->use_count
== 0);
415 ASSERT(r
->label_count
== 0);
422 mpls_remove_range(struct mpls_range
*r
)
435 mpls_lock_range(struct mpls_range
*r
)
441 mpls_unlock_range(struct mpls_range
*r
)
443 ASSERT(r
->use_count
> 0);
446 if (!r
->use_count
&& r
->removed
)
456 mpls_new_handle(struct mpls_domain
*m
, struct mpls_range
*r
)
458 struct mpls_handle
*h
= mb_allocz(m
->pool
, sizeof(struct mpls_handle
));
461 mpls_lock_range(h
->range
);
463 add_tail(&m
->handles
, &h
->n
);
469 mpls_free_handle(struct mpls_domain
*m UNUSED
, struct mpls_handle
*h
)
471 ASSERT(h
->label_count
== 0);
473 mpls_unlock_range(h
->range
);
484 mpls_new_label(struct mpls_domain
*m
, struct mpls_handle
*h
, uint n
)
486 struct mpls_range
*r
= h
->range
;
489 n
= lmap_first_zero_in_range(&m
->labels
, r
->lo
, r
->hi
);
491 if ((n
< r
->lo
) || (n
>= r
->hi
) || lmap_test(&m
->labels
, n
))
498 lmap_set(&m
->labels
, n
);
503 mpls_free_label(struct mpls_domain
*m
, struct mpls_handle
*h
, uint n
)
505 struct mpls_range
*r
= h
->range
;
507 ASSERT(lmap_test(&m
->labels
, n
));
508 lmap_clear(&m
->labels
, n
);
510 ASSERT(m
->label_count
);
513 ASSERT(r
->label_count
);
516 ASSERT(h
->label_count
);
521 mpls_move_label(struct mpls_domain
*m
, struct mpls_handle
*fh
, struct mpls_handle
*th
, uint n
)
523 struct mpls_range
*fr
= fh
->range
;
524 struct mpls_range
*tr
= th
->range
;
526 ASSERT(lmap_test(&m
->labels
, n
));
527 ASSERT((n
>= fr
->lo
) && (n
< fr
->hi
));
528 ASSERT((n
>= tr
->lo
) && (n
< tr
->hi
));
530 ASSERT(fr
->label_count
);
533 ASSERT(fh
->label_count
);
546 mpls_channel_init(struct channel
*C
, struct channel_config
*CC
)
548 struct mpls_channel
*c
= (void *) C
;
549 struct mpls_channel_config
*cc
= (void *) CC
;
551 c
->domain
= cc
->domain
->domain
;
552 c
->range
= cc
->range
->range
;
553 c
->label_policy
= cc
->label_policy
;
557 mpls_channel_start(struct channel
*C
)
559 struct mpls_channel
*c
= (void *) C
;
561 mpls_lock_domain(c
->domain
);
562 mpls_lock_range(c
->range
);
569 mpls_channel_shutdown(struct channel *C)
571 struct mpls_channel *c = (void *) C;
577 mpls_channel_cleanup(struct channel
*C
)
579 struct mpls_channel
*c
= (void *) C
;
581 mpls_unlock_range(c
->range
);
582 mpls_unlock_domain(c
->domain
);
586 mpls_channel_reconfigure(struct channel
*C
, struct channel_config
*CC
, int *import_changed
, int *export_changed UNUSED
)
588 struct mpls_channel
*c
= (void *) C
;
589 struct mpls_channel_config
*new = (void *) CC
;
591 if (new->domain
->domain
!= c
->domain
)
594 if (new->range
->range
!= c
->range
)
596 if (c
->c
.channel_state
!= CS_DOWN
)
597 mpls_unlock_range(c
->range
);
599 c
->range
= new->range
->range
;
602 if (c
->c
.channel_state
!= CS_DOWN
)
603 mpls_lock_range(c
->range
);
606 if (new->label_policy
!= c
->label_policy
)
608 c
->label_policy
= new->label_policy
;
616 mpls_channel_postconfig(struct channel_config
*CC
)
618 struct mpls_channel_config
*cc
= (void *) CC
;
621 cf_error("MPLS domain not specified");
624 cc
->range
= cc
->domain
->dynamic_range
;
626 if (cc
->range
->domain
!= cc
->domain
)
627 cf_error("MPLS label range from different MPLS domain");
630 cf_error("Routing table not specified");
633 struct channel_class channel_mpls
= {
634 .channel_size
= sizeof(struct mpls_channel
),
635 .config_size
= sizeof(struct mpls_channel_config
),
636 .init
= mpls_channel_init
,
637 .start
= mpls_channel_start
,
638 // .shutdown = mpls_channel_shutdown,
639 .cleanup
= mpls_channel_cleanup
,
640 .reconfigure
= mpls_channel_reconfigure
,
648 #define NET_KEY(fec) fec->net, fec->path_id, fec->hash
649 #define NET_NEXT(fec) fec->next_k
650 #define NET_EQ(n1,i1,h1,n2,i2,h2) h1 == h2 && i1 == i2 && net_equal(n1, n2)
651 #define NET_FN(n,i,h) h
653 #define NET_REHASH mpls_net_rehash
654 #define NET_PARAMS /8, *2, 2, 2, 8, 24
657 #define RTA_KEY(fec) fec->rta, fec->class_id, fec->hash
658 #define RTA_NEXT(fec) fec->next_k
659 #define RTA_EQ(r1,i1,h1,r2,i2,h2) h1 == h2 && r1 == r2 && i1 == i2
660 #define RTA_FN(r,i,h) h
662 #define RTA_REHASH mpls_rta_rehash
663 #define RTA_PARAMS /8, *2, 2, 2, 8, 24
666 #define LABEL_KEY(fec) fec->label
667 #define LABEL_NEXT(fec) fec->next_l
668 #define LABEL_EQ(l1,l2) l1 == l2
669 #define LABEL_FN(l) u32_hash(l)
671 #define LABEL_REHASH mpls_label_rehash
672 #define LABEL_PARAMS /8, *2, 2, 2, 8, 24
675 HASH_DEFINE_REHASH_FN(NET
, struct mpls_fec
)
676 HASH_DEFINE_REHASH_FN(RTA
, struct mpls_fec
)
677 HASH_DEFINE_REHASH_FN(LABEL
, struct mpls_fec
)
680 static void mpls_unlink_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
);
681 static void mpls_withdraw_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
);
682 static rta
* mpls_get_key_rta(struct mpls_fec_map
*m
, const rta
*src
);
684 struct mpls_fec_map
*
685 mpls_fec_map_new(pool
*pp
, struct channel
*C
, uint rts
)
687 struct pool
*p
= rp_new(pp
, "MPLS FEC map");
688 struct mpls_fec_map
*m
= mb_allocz(p
, sizeof(struct mpls_fec_map
));
689 struct mpls_channel
*c
= (void *) C
;
694 m
->domain
= c
->domain
;
695 mpls_lock_domain(m
->domain
);
697 m
->handle
= mpls_new_handle(c
->domain
, c
->range
);
699 /* net_hash and rta_hash are initialized on-demand */
700 HASH_INIT(m
->label_hash
, m
->pool
, 4);
703 m
->mpls_scope
= SCOPE_UNIVERSE
;
709 mpls_fec_map_reconfigure(struct mpls_fec_map
*m
, struct channel
*C
)
711 struct mpls_channel
*c
= (void *) C
;
713 struct mpls_handle
*old_d
= NULL
;
714 struct mpls_handle
*old_s
= NULL
;
716 /* Reallocate dynamic handle */
717 if (m
->handle
->range
!= c
->range
)
720 m
->handle
= mpls_new_handle(m
->domain
, c
->range
);
723 /* Reallocate static handle */
724 if (m
->static_handle
&& (m
->static_handle
->range
!= m
->domain
->cf
->static_range
->range
))
726 old_s
= m
->static_handle
;
727 m
->static_handle
= mpls_new_handle(m
->domain
, m
->domain
->cf
->static_range
->range
);
730 /* Skip rest if there is no change */
731 if (!old_d
&& !old_s
)
734 /* Process existing FECs */
735 HASH_WALK(m
->label_hash
, next_l
, fec
)
737 /* Skip already dead FECs */
738 if (fec
->policy
== MPLS_POLICY_NONE
)
741 /* Skip FECs with valid handle */
742 if ((fec
->handle
== m
->handle
) || (fec
->handle
== m
->static_handle
))
745 /* Try new handle for the FEC */
746 struct mpls_handle
*new = (fec
->policy
!= MPLS_POLICY_STATIC
) ? m
->handle
: m
->static_handle
;
747 if ((fec
->label
>= new->range
->lo
) && (fec
->label
< new->range
->hi
))
749 mpls_move_label(m
->domain
, fec
->handle
, new, fec
->label
);
754 /* Unlink the FEC while keep it in the label hash */
755 mpls_unlink_fec(m
, fec
);
756 fec
->policy
= MPLS_POLICY_NONE
;
760 /* Remove old unused handles */
762 if (old_d
&& !old_d
->label_count
)
763 mpls_free_handle(m
->domain
, old_d
);
765 if (old_s
&& !old_s
->label_count
)
766 mpls_free_handle(m
->domain
, old_s
);
770 mpls_fec_map_free(struct mpls_fec_map
*m
)
772 /* Free stored rtas */
773 if (m
->rta_hash
.data
)
775 HASH_WALK(m
->rta_hash
, next_k
, fec
)
783 /* Free allocated labels */
784 HASH_WALK(m
->label_hash
, next_l
, fec
)
786 mpls_free_label(m
->domain
, fec
->handle
, fec
->label
);
788 if (!fec
->policy
&& !fec
->handle
->label_count
)
789 mpls_free_handle(m
->domain
, fec
->handle
);
793 if (m
->static_handle
)
794 mpls_free_handle(m
->domain
, m
->static_handle
);
796 mpls_free_handle(m
->domain
, m
->handle
);
797 mpls_unlock_domain(m
->domain
);
803 mpls_slab(struct mpls_fec_map
*m
, uint type
)
805 ASSERT(type
<= NET_VPN6
);
806 int pos
= type
? (type
- 1) : 0;
809 m
->slabs
[pos
] = sl_new(m
->pool
, sizeof(struct mpls_fec
) + net_addr_length
[pos
+ 1]);
811 return m
->slabs
[pos
];
815 mpls_find_fec_by_label(struct mpls_fec_map
*m
, u32 label
)
817 return HASH_FIND(m
->label_hash
, LABEL
, label
);
821 mpls_get_fec_by_label(struct mpls_fec_map
*m
, u32 label
)
823 struct mpls_fec
*fec
= HASH_FIND(m
->label_hash
, LABEL
, label
);
826 return (fec
->policy
== MPLS_POLICY_STATIC
) ? fec
: NULL
;
828 if (!m
->static_handle
)
829 m
->static_handle
= mpls_new_handle(m
->domain
, m
->domain
->cf
->static_range
->range
);
831 label
= mpls_new_label(m
->domain
, m
->static_handle
, label
);
836 fec
= sl_allocz(mpls_slab(m
, 0));
839 fec
->policy
= MPLS_POLICY_STATIC
;
840 fec
->handle
= m
->static_handle
;
842 DBG("New FEC lab %u\n", fec
->label
);
844 HASH_INSERT2(m
->label_hash
, LABEL
, m
->pool
, fec
);
850 mpls_get_fec_by_net(struct mpls_fec_map
*m
, const net_addr
*net
, u64 path_id
)
852 if (!m
->net_hash
.data
)
853 HASH_INIT(m
->net_hash
, m
->pool
, 4);
855 u32 hash
= net_hash(net
) ^ u64_hash(path_id
);
856 struct mpls_fec
*fec
= HASH_FIND(m
->net_hash
, NET
, net
, path_id
, hash
);
861 u32 label
= mpls_new_label(m
->domain
, m
->handle
, 0);
866 fec
= sl_allocz(mpls_slab(m
, net
->type
));
869 fec
->path_id
= path_id
;
870 net_copy(fec
->net
, net
);
873 fec
->policy
= MPLS_POLICY_PREFIX
;
874 fec
->handle
= m
->handle
;
876 DBG("New FEC net %u\n", fec
->label
);
878 HASH_INSERT2(m
->net_hash
, NET
, m
->pool
, fec
);
879 HASH_INSERT2(m
->label_hash
, LABEL
, m
->pool
, fec
);
885 mpls_get_fec_by_rta(struct mpls_fec_map
*m
, const rta
*src
, u32 class_id
)
887 if (!m
->rta_hash
.data
)
888 HASH_INIT(m
->rta_hash
, m
->pool
, 4);
890 rta
*rta
= mpls_get_key_rta(m
, src
);
891 u32 hash
= rta
->hash_key
^ u32_hash(class_id
);
892 struct mpls_fec
*fec
= HASH_FIND(m
->rta_hash
, RTA
, rta
, class_id
, hash
);
900 u32 label
= mpls_new_label(m
->domain
, m
->handle
, 0);
908 fec
= sl_allocz(mpls_slab(m
, 0));
911 fec
->class_id
= class_id
;
915 fec
->policy
= MPLS_POLICY_AGGREGATE
;
916 fec
->handle
= m
->handle
;
918 DBG("New FEC rta %u\n", fec
->label
);
920 HASH_INSERT2(m
->rta_hash
, RTA
, m
->pool
, fec
);
921 HASH_INSERT2(m
->label_hash
, LABEL
, m
->pool
, fec
);
927 mpls_get_fec_for_vrf(struct mpls_fec_map
*m
)
929 struct mpls_fec
*fec
= m
->vrf_fec
;
934 u32 label
= mpls_new_label(m
->domain
, m
->handle
, 0);
939 fec
= sl_allocz(mpls_slab(m
, 0));
942 fec
->policy
= MPLS_POLICY_VRF
;
943 fec
->handle
= m
->handle
;
944 fec
->iface
= m
->vrf_iface
;
946 DBG("New FEC vrf %u\n", fec
->label
);
949 HASH_INSERT2(m
->label_hash
, LABEL
, m
->pool
, fec
);
955 mpls_unlink_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
)
959 case MPLS_POLICY_NONE
:
960 case MPLS_POLICY_STATIC
:
963 case MPLS_POLICY_PREFIX
:
964 HASH_REMOVE2(m
->net_hash
, NET
, m
->pool
, fec
);
967 case MPLS_POLICY_AGGREGATE
:
969 HASH_REMOVE2(m
->rta_hash
, RTA
, m
->pool
, fec
);
972 case MPLS_POLICY_VRF
:
973 ASSERT(m
->vrf_fec
== fec
);
978 bug("Unknown fec type");
983 mpls_free_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
)
985 if (fec
->state
!= MPLS_FEC_DOWN
)
986 mpls_withdraw_fec(m
, fec
);
988 DBG("Free FEC %u\n", fec
->label
);
990 mpls_free_label(m
->domain
, fec
->handle
, fec
->label
);
992 if (!fec
->policy
&& !fec
->handle
->label_count
)
993 mpls_free_handle(m
->domain
, fec
->handle
);
995 HASH_REMOVE2(m
->label_hash
, LABEL
, m
->pool
, fec
);
997 mpls_unlink_fec(m
, fec
);
1002 static inline void mpls_lock_fec(struct mpls_fec_map
*x UNUSED
, struct mpls_fec
*fec
)
1003 { if (fec
) fec
->uc
++; }
1005 static inline void mpls_unlock_fec(struct mpls_fec_map
*x
, struct mpls_fec
*fec
)
1006 { if (fec
&& !--fec
->uc
) mpls_free_fec(x
, fec
); }
1009 mpls_damage_fec(struct mpls_fec_map
*m UNUSED
, struct mpls_fec
*fec
)
1011 if (fec
&& (fec
->state
== MPLS_FEC_CLEAN
))
1012 fec
->state
= MPLS_FEC_DIRTY
;
1016 mpls_get_key_rta(struct mpls_fec_map
*m
, const rta
*src
)
1018 rta
*a
= allocz(RTA_MAX_SIZE
);
1020 a
->source
= m
->mpls_rts
;
1021 a
->scope
= m
->mpls_scope
;
1023 if (!src
->hostentry
)
1025 /* Just copy the nexthop */
1026 a
->dest
= src
->dest
;
1027 nexthop_link(a
, &src
->nh
);
1031 /* Keep the hostentry */
1032 a
->hostentry
= src
->hostentry
;
1034 /* Keep the original labelstack */
1035 const u32
*labels
= &src
->nh
.label
[src
->nh
.labels
- src
->nh
.labels_orig
];
1036 a
->nh
.labels
= a
->nh
.labels_orig
= src
->nh
.labels_orig
;
1037 memcpy(a
->nh
.label
, labels
, src
->nh
.labels_orig
* sizeof(u32
));
1040 return rta_lookup(a
);
1044 mpls_announce_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
, const rta
*src
)
1046 rta
*a
= allocz(RTA_MAX_SIZE
);
1048 a
->source
= m
->mpls_rts
;
1049 a
->scope
= m
->mpls_scope
;
1051 if (!src
->hostentry
)
1053 /* Just copy the nexthop */
1054 a
->dest
= src
->dest
;
1055 nexthop_link(a
, &src
->nh
);
1059 const u32
*labels
= &src
->nh
.label
[src
->nh
.labels
- src
->nh
.labels_orig
];
1060 mpls_label_stack ms
;
1062 /* Reconstruct the original labelstack */
1063 ms
.len
= src
->nh
.labels_orig
;
1064 memcpy(ms
.stack
, labels
, src
->nh
.labels_orig
* sizeof(u32
));
1066 /* The same hostentry, but different dependent table */
1067 struct hostentry
*s
= src
->hostentry
;
1068 rta_set_recursive_next_hop(m
->channel
->table
, a
, s
->owner
, s
->addr
, s
->link
, &ms
);
1071 net_addr_mpls n
= NET_ADDR_MPLS(fec
->label
);
1073 rte
*e
= rte_get_temp(rta_lookup(a
), m
->channel
->proto
->main_source
);
1076 fec
->state
= MPLS_FEC_CLEAN
;
1077 rte_update2(m
->channel
, (net_addr
*) &n
, e
, m
->channel
->proto
->main_source
);
1081 mpls_withdraw_fec(struct mpls_fec_map
*m
, struct mpls_fec
*fec
)
1083 net_addr_mpls n
= NET_ADDR_MPLS(fec
->label
);
1085 fec
->state
= MPLS_FEC_DOWN
;
1086 rte_update2(m
->channel
, (net_addr
*) &n
, NULL
, m
->channel
->proto
->main_source
);
1090 mpls_apply_fec(rte
*r
, struct mpls_fec
*fec
, linpool
*lp
)
1092 struct ea_list
*ea
= lp_allocz(lp
, sizeof(struct ea_list
) + 2 * sizeof(eattr
));
1094 rta
*old_attrs
= r
->attrs
;
1096 if (rta_is_cached(old_attrs
))
1097 r
->attrs
= rta_do_cow(r
->attrs
, lp
);
1099 *ea
= (struct ea_list
) {
1100 .next
= r
->attrs
->eattrs
,
1101 .flags
= EALF_SORTED
,
1105 ea
->attrs
[0] = (struct eattr
) {
1106 .id
= EA_MPLS_LABEL
,
1107 .type
= EAF_TYPE_INT
,
1108 .u
.data
= fec
->label
,
1111 ea
->attrs
[1] = (struct eattr
) {
1112 .id
= EA_MPLS_POLICY
,
1113 .type
= EAF_TYPE_INT
,
1114 .u
.data
= fec
->policy
,
1117 r
->attrs
->eattrs
= ea
;
1119 if (fec
->policy
== MPLS_POLICY_VRF
)
1121 r
->attrs
->hostentry
= NULL
;
1122 r
->attrs
->dest
= RTD_UNICAST
;
1123 r
->attrs
->nh
= (struct nexthop
) { .iface
= fec
->iface
};
1126 if (rta_is_cached(old_attrs
))
1128 r
->attrs
= rta_lookup(r
->attrs
);
1129 rta_free(old_attrs
);
1135 mpls_handle_rte(struct mpls_fec_map
*m
, const net_addr
*n
, rte
*r
, linpool
*lp
, struct mpls_fec
**locked_fec
)
1137 ASSERT(!(r
->flags
& REF_COW
));
1139 struct mpls_fec
*fec
= NULL
;
1141 /* Select FEC for route */
1142 uint policy
= ea_get_int(r
->attrs
->eattrs
, EA_MPLS_POLICY
, 0);
1145 case MPLS_POLICY_NONE
:
1148 case MPLS_POLICY_STATIC
:;
1149 uint label
= ea_get_int(r
->attrs
->eattrs
, EA_MPLS_LABEL
, 0);
1154 fec
= mpls_get_fec_by_label(m
, label
);
1157 log(L_WARN
"Static label %u failed for %N from %s",
1158 label
, n
, r
->sender
->proto
->name
);
1162 mpls_damage_fec(m
, fec
);
1165 case MPLS_POLICY_PREFIX
:
1166 fec
= mpls_get_fec_by_net(m
, n
, r
->src
->private_id
);
1167 mpls_damage_fec(m
, fec
);
1170 case MPLS_POLICY_AGGREGATE
:;
1171 uint
class = ea_get_int(r
->attrs
->eattrs
, EA_MPLS_CLASS
, 0);
1172 fec
= mpls_get_fec_by_rta(m
, r
->attrs
, class);
1175 case MPLS_POLICY_VRF
:
1179 fec
= mpls_get_fec_for_vrf(m
);
1183 log(L_WARN
"Route %N has invalid MPLS policy %u", n
, policy
);
1187 /* Label allocation failure */
1190 log(L_WARN
"Label allocation in range %s failed for %N from %s",
1191 m
->handle
->range
->name
, n
, r
->sender
->proto
->name
);
1195 /* Temporarily lock FEC */
1196 mpls_lock_fec(m
, fec
);
1199 /* Apply FEC label to route */
1200 mpls_apply_fec(r
, fec
, lp
);
1202 /* Announce MPLS rule for new/updated FEC */
1203 if (fec
->state
!= MPLS_FEC_CLEAN
)
1204 mpls_announce_fec(m
, fec
, r
->attrs
);
1210 mpls_handle_rte_cleanup(struct mpls_fec_map
*m
, struct mpls_fec
**locked_fec
)
1212 /* Unlock temporarily locked FEC from mpls_handle_rte() */
1215 mpls_unlock_fec(m
, *locked_fec
);
1221 mpls_rte_insert(net
*n UNUSED
, rte
*r
)
1223 struct proto
*p
= r
->src
->proto
;
1224 struct mpls_fec_map
*m
= p
->mpls_map
;
1226 uint label
= ea_get_int(r
->attrs
->eattrs
, EA_MPLS_LABEL
, 0);
1230 struct mpls_fec
*fec
= mpls_find_fec_by_label(m
, label
);
1234 mpls_lock_fec(m
, fec
);
1238 mpls_rte_remove(net
*n UNUSED
, rte
*r
)
1240 struct proto
*p
= r
->src
->proto
;
1241 struct mpls_fec_map
*m
= p
->mpls_map
;
1243 uint label
= ea_get_int(r
->attrs
->eattrs
, EA_MPLS_LABEL
, 0);
1247 struct mpls_fec
*fec
= mpls_find_fec_by_label(m
, label
);
1251 mpls_unlock_fec(m
, fec
);
1255 mpls_show_ranges_rng(struct mpls_show_ranges_cmd
*cmd
, struct mpls_range
*r
)
1257 uint last
= lmap_last_one_in_range(&cmd
->dom
->labels
, r
->lo
, r
->hi
);
1258 if (last
== r
->hi
) last
= 0;
1260 cli_msg(-1026, "%-11s %7u %7u %7u %7u %7u",
1261 r
->name
, r
->lo
, r
->hi
- r
->lo
, r
->hi
, r
->label_count
, last
);
1265 mpls_show_ranges_dom(struct mpls_show_ranges_cmd
*cmd
, struct mpls_domain
*m
)
1271 cli_msg(-1026, "MPLS domain %s:", m
->name
);
1272 cli_msg(-1026, "%-11s %7s %7s %7s %7s %7s",
1273 "Range", "Start", "Length", "End", "Labels", "Last");
1276 mpls_show_ranges_rng(cmd
, cmd
->range
->range
);
1279 struct mpls_range
*r
;
1280 WALK_LIST(r
, m
->ranges
)
1282 mpls_show_ranges_rng(cmd
, r
);
1287 mpls_show_ranges(struct mpls_show_ranges_cmd
*cmd
)
1290 mpls_show_ranges_dom(cmd
, cmd
->domain
->domain
);
1293 struct mpls_domain
*m
;
1294 WALK_LIST(m
, mpls_domains
)
1295 mpls_show_ranges_dom(cmd
, m
);