2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/ip/ip.h>
17 #include <vnet/dpo/mpls_label_dpo.h>
18 #include <vnet/mpls/mpls.h>
19 #include <vnet/dpo/drop_dpo.h>
23 #ifndef CLIB_MARCH_VARIANT
25 * pool of all MPLS Label DPOs
27 mpls_label_dpo_t *mpls_label_dpo_pool;
30 * Strings for the flags
32 const char* mpls_label_dpo_attr_names[] = MPLS_LABEL_DPO_ATTR_NAMES;
35 * registered DPO types for each of the label sub-types. And there's a
36 * subtype for each of the flag combinations.
38 static dpo_type_t mpls_label_dpo_types[1 << MPLS_LABEL_DPO_ATTR_MAX];
40 static mpls_label_dpo_t *
41 mpls_label_dpo_alloc (void)
43 mpls_label_dpo_t *mld;
47 dpo_pool_barrier_sync (vm, mpls_label_dpo_pool, did_barrier_sync);
48 pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
49 dpo_pool_barrier_release (vm, did_barrier_sync);
51 clib_memset(mld, 0, sizeof(*mld));
53 dpo_reset(&mld->mld_dpo);
59 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
61 return (mld - mpls_label_dpo_pool);
65 mpls_label_dpo_create (fib_mpls_label_t *label_stack,
67 dpo_proto_t payload_proto,
68 mpls_label_dpo_flags_t flags,
69 const dpo_id_t *parent,
72 mpls_label_dpo_t *mld;
76 if ((DPO_PROTO_IP4 != payload_proto) &&
77 (DPO_PROTO_IP6 != payload_proto))
80 * remove unsupported configuration
82 flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
85 mld = mpls_label_dpo_alloc();
86 mld->mld_flags = flags;
87 mld->mld_payload_proto = payload_proto;
88 dtype = mpls_label_dpo_types[flags];
90 if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
92 clib_warning("Label stack size exceeded");
94 mld->mld_payload_proto,
96 drop_dpo_get(mld->mld_payload_proto));
100 mld->mld_n_labels = vec_len(label_stack);
101 mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
104 * construct label rewrite headers for each value passed.
105 * get the header in network byte order since we will paint it
106 * on a packet in the data-plane
108 for (ii = 0; ii < mld->mld_n_labels-1; ii++)
110 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
111 label_stack[ii].fml_value);
112 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
113 label_stack[ii].fml_exp);
114 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
116 if (0 != label_stack[ii].fml_ttl)
118 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
119 label_stack[ii].fml_ttl);
123 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
124 MPLS_LABEL_DEFAULT_TTL);
126 mld->mld_hdr[ii].label_exp_s_ttl =
127 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
131 * the inner most label
133 ii = mld->mld_n_labels-1;
135 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
136 label_stack[ii].fml_value);
137 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
138 label_stack[ii].fml_exp);
139 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
140 if (0 != label_stack[ii].fml_ttl)
142 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
143 label_stack[ii].fml_ttl);
147 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
148 MPLS_LABEL_DEFAULT_TTL);
150 mld->mld_hdr[ii].label_exp_s_ttl =
151 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
154 * pipe/uniform mode is only supported for the bottom of stack label
156 if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
158 mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
162 mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
164 dtype = mpls_label_dpo_types[mld->mld_flags];
167 * stack this label object on its parent.
170 mld->mld_payload_proto,
177 mld->mld_payload_proto,
178 mpls_label_dpo_get_index(mld));
182 format_mpls_label_dpo_flags (u8 *s, va_list *args)
184 mpls_label_dpo_flags_t flags = va_arg (*args, int);
185 mpls_label_dpo_attr_t attr;
187 FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
189 if ((1 << attr) & flags)
191 s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
199 format_mpls_label_dpo (u8 *s, va_list *args)
201 index_t index = va_arg (*args, index_t);
202 u32 indent = va_arg (*args, u32);
203 mpls_unicast_header_t hdr;
204 mpls_label_dpo_t *mld;
207 if (pool_is_free_index(mpls_label_dpo_pool, index))
210 * the packet trace can be printed after the DPO has been deleted
212 return (format(s, "mpls-label[???,%d]:", index));
215 mld = mpls_label_dpo_get(index);
216 s = format(s, "mpls-label[%U@%d]:",
217 format_mpls_label_dpo_flags,
218 (int) mld->mld_flags, index);
220 for (ii = 0; ii < mld->mld_n_labels; ii++)
222 hdr.label_exp_s_ttl =
223 clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
224 s = format(s, "%U", format_mpls_header, hdr);
227 s = format(s, "\n%U", format_white_space, indent);
228 s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
234 mpls_label_dpo_lock (dpo_id_t *dpo)
236 mpls_label_dpo_t *mld;
238 mld = mpls_label_dpo_get(dpo->dpoi_index);
244 mpls_label_dpo_unlock (dpo_id_t *dpo)
246 mpls_label_dpo_t *mld;
248 mld = mpls_label_dpo_get(dpo->dpoi_index);
252 if (0 == mld->mld_locks)
254 dpo_reset(&mld->mld_dpo);
255 pool_put(mpls_label_dpo_pool, mld);
258 #endif /* CLIB_MARCH_VARIANT */
261 * @brief A struct to hold tracing information for the MPLS label imposition
264 typedef struct mpls_label_imposition_trace_t_
267 * The MPLS header imposed
269 mpls_unicast_header_t hdr;
272 * TTL imposed - only valid for uniform LSPs
277 * TTL imposed - only valid for uniform LSPs
280 } mpls_label_imposition_trace_t;
282 always_inline mpls_unicast_header_t *
283 mpls_label_paint (vlib_buffer_t * b0,
284 mpls_label_dpo_t *mld0)
286 mpls_unicast_header_t *hdr0;
288 vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
290 hdr0 = vlib_buffer_get_current(b0);
292 if (1 == mld0->mld_n_labels)
294 /* optimise for the common case of one label */
295 *hdr0 = mld0->mld_hdr[0];
299 clib_memcpy_fast(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
300 hdr0 = hdr0 + (mld0->mld_n_labels - 1);
307 * Paint on an MPLS label and fixup the TTL
309 always_inline mpls_unicast_header_t *
310 mpls_label_paint_w_ttl (vlib_buffer_t * b0,
311 mpls_label_dpo_t *mld0,
314 mpls_unicast_header_t *hdr0;
316 hdr0 = mpls_label_paint(b0, mld0);
318 /* fixup the TTL for the inner most label */
319 ((char*)hdr0)[3] = ttl0;
325 * Paint on an MPLS label and fixup the TTL and EXP bits.
327 always_inline mpls_unicast_header_t *
328 mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0,
329 mpls_label_dpo_t *mld0,
333 mpls_unicast_header_t *hdr0;
335 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
337 /* fixup the EXP for the inner most label */
338 ((char*)hdr0)[2] |= (exp0 << 1);
344 * Paint on an MPLS label and fixup the TTL and EXP bits
345 * When the EXP bits are *already* bit shift to the correct place in
346 * in the 2nd byte (i.e. they were read from another label)
348 always_inline mpls_unicast_header_t *
349 mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0,
350 mpls_label_dpo_t *mld0,
354 mpls_unicast_header_t *hdr0;
356 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
358 /* fixup the EXP for the inner most label */
359 ((char*)hdr0)[2] |= exp0;
365 mpls_label_imposition_inline (vlib_main_t * vm,
366 vlib_node_runtime_t * node,
367 vlib_frame_t * from_frame,
368 const dpo_proto_t dproto,
369 const mpls_label_dpo_flags_t flags)
371 u32 n_left_from, next_index, * from, * to_next;
373 from = vlib_frame_vector_args (from_frame);
374 n_left_from = from_frame->n_vectors;
376 next_index = node->cached_next_index;
378 while (n_left_from > 0)
382 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
384 while (n_left_from >= 8 && n_left_to_next >= 4)
386 u32 bi0, mldi0, bi1, mldi1, bi2, mldi2, bi3, mldi3;
387 mpls_unicast_header_t *hdr0, *hdr1, *hdr2, *hdr3;
388 mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3;
389 vlib_buffer_t * b0, *b1, * b2, *b3;
390 u32 next0, next1, next2, next3;
391 u8 ttl0, ttl1, ttl2, ttl3;
392 u8 exp0, exp1, exp2, exp3;
394 bi0 = to_next[0] = from[0];
395 bi1 = to_next[1] = from[1];
396 bi2 = to_next[2] = from[2];
397 bi3 = to_next[3] = from[3];
399 /* Prefetch next iteration. */
401 vlib_buffer_t *p4, *p5, *p6, *p7;
403 p4 = vlib_get_buffer (vm, from[4]);
404 p5 = vlib_get_buffer (vm, from[5]);
405 p6 = vlib_get_buffer (vm, from[6]);
406 p7 = vlib_get_buffer (vm, from[7]);
408 vlib_prefetch_buffer_header (p4, STORE);
409 vlib_prefetch_buffer_header (p5, STORE);
410 vlib_prefetch_buffer_header (p6, STORE);
411 vlib_prefetch_buffer_header (p7, STORE);
413 CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
414 CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
415 CLIB_PREFETCH (p6->data, sizeof (hdr0[0]), STORE);
416 CLIB_PREFETCH (p7->data, sizeof (hdr0[0]), STORE);
424 b0 = vlib_get_buffer (vm, bi0);
425 b1 = vlib_get_buffer (vm, bi1);
426 b2 = vlib_get_buffer (vm, bi2);
427 b3 = vlib_get_buffer (vm, bi3);
429 /* dst lookup was done by ip4 lookup */
430 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
431 mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
432 mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
433 mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
434 mld0 = mpls_label_dpo_get(mldi0);
435 mld1 = mpls_label_dpo_get(mldi1);
436 mld2 = mpls_label_dpo_get(mldi2);
437 mld3 = mpls_label_dpo_get(mldi3);
439 if (DPO_PROTO_MPLS != dproto)
442 * These are the non-MPLS payload imposition cases.
445 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
446 vnet_buffer (b1)->l3_hdr_offset = b1->current_data;
447 vnet_buffer (b2)->l3_hdr_offset = b2->current_data;
448 vnet_buffer (b3)->l3_hdr_offset = b3->current_data;
450 if (DPO_PROTO_IP4 == dproto)
452 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
453 ip4_header_t * ip1 = vlib_buffer_get_current(b1);
454 ip4_header_t * ip2 = vlib_buffer_get_current(b2);
455 ip4_header_t * ip3 = vlib_buffer_get_current(b3);
457 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
460 * decrement the TTL on ingress to the LSP
467 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
468 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
469 checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
470 checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
472 checksum0 += checksum0 >= 0xffff;
473 checksum1 += checksum1 >= 0xffff;
474 checksum2 += checksum2 >= 0xffff;
475 checksum3 += checksum3 >= 0xffff;
477 ip0->checksum = checksum0;
478 ip1->checksum = checksum1;
479 ip2->checksum = checksum2;
480 ip3->checksum = checksum3;
488 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
494 /* by default copy the 3 most significant bits */
495 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
496 exp1 = ip_dscp_to_mpls_exp(ip1->tos);
497 exp2 = ip_dscp_to_mpls_exp(ip2->tos);
498 exp3 = ip_dscp_to_mpls_exp(ip3->tos);
501 /* save the payload proto information in mpls opaque */
502 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
503 vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP4;
504 vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP4;
505 vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP4;
507 else if (DPO_PROTO_IP6 == dproto)
510 * decrement the TTL on ingress to the LSP
512 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
513 ip6_header_t * ip1 = vlib_buffer_get_current(b1);
514 ip6_header_t * ip2 = vlib_buffer_get_current(b2);
515 ip6_header_t * ip3 = vlib_buffer_get_current(b3);
517 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
524 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
526 ttl0 = ip0->hop_limit;
527 ttl1 = ip1->hop_limit;
528 ttl2 = ip2->hop_limit;
529 ttl3 = ip3->hop_limit;
530 /* by default copy the 3 most significant bits */
531 exp0 = ip_dscp_to_mpls_exp(
532 ip6_traffic_class_network_order(ip0));
533 exp1 = ip_dscp_to_mpls_exp(
534 ip6_traffic_class_network_order(ip1));
535 exp2 = ip_dscp_to_mpls_exp(
536 ip6_traffic_class_network_order(ip2));
537 exp3 = ip_dscp_to_mpls_exp(
538 ip6_traffic_class_network_order(ip3));
541 /* save the payload proto information in mpls opaque */
542 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
543 vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP6;
544 vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP6;
545 vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP6;
550 * nothing to change in the ethernet header
552 ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
553 exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
556 * These are the non-MPLS payload imposition cases.
557 * Based on the LSP mode either, for uniform, copy down the TTL
558 * and EXP from the payload or, for pipe mode, slap on the value
559 * requested from config
561 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
563 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
564 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
565 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
566 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
570 hdr0 = mpls_label_paint(b0, mld0);
571 hdr1 = mpls_label_paint(b1, mld1);
572 hdr2 = mpls_label_paint(b2, mld2);
573 hdr3 = mpls_label_paint(b3, mld3);
579 * else, the packet to be encapped is an MPLS packet
580 * there are two cases to consider:
581 * 1 - this is an MPLS label swap at an LSP midpoint.
582 * recognisable because mpls.first = 1. In this case the
583 * TTL must be set to the current value -1.
584 * 2 - The MPLS packet is recursing (or being injected into)
585 * this LSP, in which case the pipe/uniform rules apply
588 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
591 * The first label to be imposed on the packet. this is a
592 * label swap.in which case we stashed the TTL and EXP bits
593 * in the packet in the lookup node
595 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
597 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
598 exp0 = vnet_buffer(b0)->mpls.exp;
599 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
604 * not the first label. implying we are recusring down a
605 * chain of output labels. Each layer is considered a new
606 * LSP - hence the TTL/EXP are pipe/uniform handled
608 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
610 hdr0 = vlib_buffer_get_current(b0);
611 ttl0 = ((u8*)hdr0)[3];
612 exp0 = ((u8*)hdr0)[2] & 0xe;
613 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
617 hdr0 = mpls_label_paint(b0, mld0);
620 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
622 ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
624 ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
625 exp1 = vnet_buffer(b1)->mpls.exp;
626 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
630 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
632 hdr1 = vlib_buffer_get_current(b1);
633 ttl1 = ((u8*)hdr1)[3];
634 exp1 = ((u8*)hdr1)[2] & 0xe;
635 hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
639 hdr1 = mpls_label_paint(b1, mld1);
642 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
644 ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
646 ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
647 exp2 = vnet_buffer(b2)->mpls.exp;
648 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
652 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
654 hdr2 = vlib_buffer_get_current(b2);
655 ttl2 = ((u8*)hdr2)[3];
656 exp2 = ((u8*)hdr2)[2] & 0xe;
657 hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
661 hdr2 = mpls_label_paint(b2, mld2);
664 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
666 ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
668 ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
669 exp3 = vnet_buffer(b3)->mpls.exp;
670 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
674 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
676 hdr3 = vlib_buffer_get_current(b3);
677 ttl3 = ((u8*)hdr3)[3];
678 exp3 = ((u8*)hdr3)[2] & 0xe;
679 hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
683 hdr3 = mpls_label_paint(b3, mld3);
687 vnet_buffer(b0)->mpls.first = 0;
688 vnet_buffer(b1)->mpls.first = 0;
689 vnet_buffer(b2)->mpls.first = 0;
690 vnet_buffer(b3)->mpls.first = 0;
693 next0 = mld0->mld_dpo.dpoi_next_node;
694 next1 = mld1->mld_dpo.dpoi_next_node;
695 next2 = mld2->mld_dpo.dpoi_next_node;
696 next3 = mld3->mld_dpo.dpoi_next_node;
698 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
699 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
700 vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
701 vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
703 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
705 mpls_label_imposition_trace_t *tr =
706 vlib_add_trace (vm, node, b0, sizeof (*tr));
708 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
715 tr->ttl = tr->exp = 0;
718 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
720 mpls_label_imposition_trace_t *tr =
721 vlib_add_trace (vm, node, b1, sizeof (*tr));
723 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
730 tr->ttl = tr->exp = 0;
733 if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
735 mpls_label_imposition_trace_t *tr =
736 vlib_add_trace (vm, node, b2, sizeof (*tr));
738 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
745 tr->ttl = tr->exp = 0;
748 if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
750 mpls_label_imposition_trace_t *tr =
751 vlib_add_trace (vm, node, b3, sizeof (*tr));
753 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
760 tr->ttl = tr->exp = 0;
764 vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
767 next0, next1, next2, next3);
770 while (n_left_from > 0 && n_left_to_next > 0)
772 mpls_unicast_header_t *hdr0;
773 mpls_label_dpo_t *mld0;
786 b0 = vlib_get_buffer (vm, bi0);
788 /* dst lookup was done by ip4 lookup */
789 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
790 mld0 = mpls_label_dpo_get(mldi0);
792 if (DPO_PROTO_MPLS != dproto)
794 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
796 if (DPO_PROTO_IP4 == dproto)
799 * decrement the TTL on ingress to the LSP
801 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
802 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
806 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
807 checksum0 += checksum0 >= 0xffff;
809 ip0->checksum = checksum0;
812 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
815 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
818 /* save the payload proto information in mpls opaque */
819 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
821 else if (DPO_PROTO_IP6 == dproto)
824 * decrement the TTL on ingress to the LSP
826 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
828 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
832 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
834 ttl0 = ip0->hop_limit;
835 exp0 = ip_dscp_to_mpls_exp(
836 ip6_traffic_class_network_order(ip0));
839 /* save the payload proto information in mpls opaque */
840 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
845 * nothing to change in the ethernet header
847 ttl0 = MPLS_LABEL_DEFAULT_TTL;
848 exp0 = MPLS_LABEL_DEFAULT_EXP;
852 * These are the non-MPLS payload imposition cases.
853 * Based on the LSP mode either, for uniform, copy down the TTL
854 * from the payload or, for pipe mode, slap on the value
855 * requested from config
857 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
859 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
863 hdr0 = mpls_label_paint(b0, mld0);
868 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
870 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
872 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
873 exp0 = vnet_buffer(b0)->mpls.exp;
874 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
878 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
880 hdr0 = vlib_buffer_get_current(b0);
881 ttl0 = ((u8*)hdr0)[3];
882 exp0 = ((u8*)hdr0)[2] & 0xe;
883 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
887 hdr0 = mpls_label_paint(b0, mld0);
891 vnet_buffer(b0)->mpls.first = 0;
894 next0 = mld0->mld_dpo.dpoi_next_node;
895 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
897 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
899 mpls_label_imposition_trace_t *tr =
900 vlib_add_trace (vm, node, b0, sizeof (*tr));
902 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
909 tr->ttl = tr->exp = 0;
913 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
914 n_left_to_next, bi0, next0);
916 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
918 return from_frame->n_vectors;
922 format_mpls_label_imposition_trace (u8 * s, va_list * args)
924 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
925 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
926 mpls_label_imposition_trace_t * t;
927 mpls_unicast_header_t hdr;
930 t = va_arg (*args, mpls_label_imposition_trace_t *);
931 indent = format_get_indent (s);
932 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
934 s = format (s, "%Umpls-header:%U",
935 format_white_space, indent,
936 format_mpls_header, hdr);
940 VLIB_NODE_FN (mpls_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
941 vlib_node_runtime_t * node,
942 vlib_frame_t * frame)
944 return (mpls_label_imposition_inline(vm, node, frame,
946 MPLS_LABEL_DPO_FLAG_NONE));
949 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = {
950 .name = "mpls-label-imposition-pipe",
951 .vector_size = sizeof (u32),
953 .format_trace = format_mpls_label_imposition_trace,
960 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
961 vlib_node_runtime_t * node,
962 vlib_frame_t * frame)
964 return (mpls_label_imposition_inline(vm, node, frame,
966 MPLS_LABEL_DPO_FLAG_NONE));
969 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
970 .name = "ip4-mpls-label-imposition-pipe",
971 .vector_size = sizeof (u32),
973 .format_trace = format_mpls_label_imposition_trace,
980 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
981 vlib_node_runtime_t * node,
982 vlib_frame_t * frame)
984 return (mpls_label_imposition_inline(vm, node, frame,
986 MPLS_LABEL_DPO_FLAG_NONE));
989 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
990 .name = "ip6-mpls-label-imposition-pipe",
991 .vector_size = sizeof (u32),
993 .format_trace = format_mpls_label_imposition_trace,
1000 VLIB_NODE_FN (ethernet_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
1001 vlib_node_runtime_t * node,
1002 vlib_frame_t * frame)
1004 return (mpls_label_imposition_inline(vm, node, frame,
1006 MPLS_LABEL_DPO_FLAG_NONE));
1009 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
1010 .name = "ethernet-mpls-label-imposition-pipe",
1011 .vector_size = sizeof (u32),
1013 .format_trace = format_mpls_label_imposition_trace,
1020 VLIB_NODE_FN (mpls_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1021 vlib_node_runtime_t * node,
1022 vlib_frame_t * frame)
1024 return (mpls_label_imposition_inline(vm, node, frame,
1026 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1029 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
1030 .name = "mpls-label-imposition-uniform",
1031 .vector_size = sizeof (u32),
1033 .format_trace = format_mpls_label_imposition_trace,
1040 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1041 vlib_node_runtime_t * node,
1042 vlib_frame_t * frame)
1044 return (mpls_label_imposition_inline(vm, node, frame,
1046 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1049 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = {
1050 .name = "ip4-mpls-label-imposition-uniform",
1051 .vector_size = sizeof (u32),
1053 .format_trace = format_mpls_label_imposition_trace,
1060 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1061 vlib_node_runtime_t * node,
1062 vlib_frame_t * frame)
1064 return (mpls_label_imposition_inline(vm, node, frame,
1066 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1069 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1070 .name = "ip6-mpls-label-imposition-uniform",
1071 .vector_size = sizeof (u32),
1073 .format_trace = format_mpls_label_imposition_trace,
1080 VLIB_NODE_FN (ethernet_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1081 vlib_node_runtime_t * node,
1082 vlib_frame_t * frame)
1084 return (mpls_label_imposition_inline(vm, node, frame,
1086 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1089 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1090 .name = "ethernet-mpls-label-imposition-uniform",
1091 .vector_size = sizeof (u32),
1093 .format_trace = format_mpls_label_imposition_trace,
1101 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1102 vlib_node_runtime_t * node,
1103 vlib_frame_t * frame)
1105 return (mpls_label_imposition_inline(vm, node, frame,
1107 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1110 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1111 .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1112 .vector_size = sizeof (u32),
1114 .format_trace = format_mpls_label_imposition_trace,
1121 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1122 vlib_node_runtime_t * node,
1123 vlib_frame_t * frame)
1125 return (mpls_label_imposition_inline(vm, node, frame,
1127 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1130 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1131 .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1132 .vector_size = sizeof (u32),
1134 .format_trace = format_mpls_label_imposition_trace,
1141 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1142 vlib_node_runtime_t * node,
1143 vlib_frame_t * frame)
1145 return (mpls_label_imposition_inline(vm, node, frame,
1147 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1148 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1151 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1152 .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1153 .vector_size = sizeof (u32),
1155 .format_trace = format_mpls_label_imposition_trace,
1162 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1163 vlib_node_runtime_t * node,
1164 vlib_frame_t * frame)
1166 return (mpls_label_imposition_inline(vm, node, frame,
1168 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1169 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1172 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1173 .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1174 .vector_size = sizeof (u32),
1176 .format_trace = format_mpls_label_imposition_trace,
1184 #ifndef CLIB_MARCH_VARIANT
1186 mpls_label_dpo_mem_show (void)
1188 fib_show_memory_usage("MPLS label",
1189 pool_elts(mpls_label_dpo_pool),
1190 pool_len(mpls_label_dpo_pool),
1191 sizeof(mpls_label_dpo_t));
1195 * Interpose a label DPO. used in the FIB unit tests
1198 mpls_label_interpose (const dpo_id_t *original,
1199 const dpo_id_t *parent,
1202 mpls_label_dpo_t *mld, *mld_clone;
1204 mld_clone = mpls_label_dpo_alloc();
1205 mld = mpls_label_dpo_get(original->dpoi_index);
1207 mld_clone->mld_locks = 0;
1208 clib_memcpy_fast(&mld_clone->mld_hdr,
1210 sizeof(mld_clone->mld_hdr));
1211 mld_clone->mld_payload_proto = mld->mld_payload_proto;
1212 mld_clone->mld_n_labels = mld->mld_n_labels;
1213 mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1215 dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1216 mld_clone->mld_payload_proto,
1217 &mld_clone->mld_dpo,
1221 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1222 mld_clone->mld_payload_proto,
1223 mpls_label_dpo_get_index(mld_clone));
1227 mpls_label_dpo_get_mtu (const dpo_id_t *dpo)
1229 mpls_label_dpo_t *mld;
1231 mld = mpls_label_dpo_get(dpo->dpoi_index);
1233 /* return the parent's MTU minus the amount of header
1234 * this DPO imposes */
1235 return (dpo_get_mtu (&mld->mld_dpo) - sizeof(mpls_label_t) * mld->mld_n_labels);
1238 const static dpo_vft_t mld_vft = {
1239 .dv_lock = mpls_label_dpo_lock,
1240 .dv_unlock = mpls_label_dpo_unlock,
1241 .dv_format = format_mpls_label_dpo,
1242 .dv_mem_show = mpls_label_dpo_mem_show,
1243 .dv_mk_interpose = mpls_label_interpose,
1244 .dv_get_mtu = mpls_label_dpo_get_mtu,
1247 const static char* const mpls_label_imp_pipe_ip4_nodes[] =
1249 "ip4-mpls-label-imposition-pipe",
1252 const static char* const mpls_label_imp_pipe_ip6_nodes[] =
1254 "ip6-mpls-label-imposition-pipe",
1257 const static char* const mpls_label_imp_pipe_mpls_nodes[] =
1259 "mpls-label-imposition-pipe",
1262 const static char* const mpls_label_imp_pipe_ethernet_nodes[] =
1264 "ethernet-mpls-label-imposition-pipe",
1268 const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] =
1270 [DPO_PROTO_IP4] = mpls_label_imp_pipe_ip4_nodes,
1271 [DPO_PROTO_IP6] = mpls_label_imp_pipe_ip6_nodes,
1272 [DPO_PROTO_MPLS] = mpls_label_imp_pipe_mpls_nodes,
1273 [DPO_PROTO_ETHERNET] = mpls_label_imp_pipe_ethernet_nodes,
1276 const static char* const mpls_label_imp_uniform_ip4_nodes[] =
1278 "ip4-mpls-label-imposition-uniform",
1281 const static char* const mpls_label_imp_uniform_ip6_nodes[] =
1283 "ip6-mpls-label-imposition-uniform",
1286 const static char* const mpls_label_imp_uniform_mpls_nodes[] =
1288 "mpls-label-imposition-uniform",
1291 const static char* const mpls_label_imp_uniform_ethernet_nodes[] =
1293 "ethernet-mpls-label-imposition-uniform",
1297 const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] =
1299 [DPO_PROTO_IP4] = mpls_label_imp_uniform_ip4_nodes,
1300 [DPO_PROTO_IP6] = mpls_label_imp_uniform_ip6_nodes,
1301 [DPO_PROTO_MPLS] = mpls_label_imp_uniform_mpls_nodes,
1302 [DPO_PROTO_ETHERNET] = mpls_label_imp_uniform_ethernet_nodes,
1305 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] =
1307 "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1310 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] =
1312 "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1316 const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1318 [DPO_PROTO_IP4] = mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes,
1319 [DPO_PROTO_IP6] = mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes,
1322 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] =
1324 "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1327 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] =
1329 "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1333 const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1335 [DPO_PROTO_IP4] = mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes,
1336 [DPO_PROTO_IP6] = mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes,
1340 mpls_label_dpo_module_init (void)
1342 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] =
1343 dpo_register_new_type(&mld_vft,
1344 mpls_label_imp_pipe_nodes);
1345 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1346 dpo_register_new_type(&mld_vft,
1347 mpls_label_imp_pipe_no_ip_tll_decr_nodes);
1348 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] =
1349 dpo_register_new_type(&mld_vft,
1350 mpls_label_imp_uniform_nodes);
1351 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1352 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1353 dpo_register_new_type(&mld_vft,
1354 mpls_label_imp_uniform_no_ip_tll_decr_nodes);
1358 mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1360 return (mpls_label_dpo_types[flags]);
1362 #endif /* CLIB_MARCH_VARIANT */