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>
21 #ifndef CLIB_MARCH_VARIANT
23 * pool of all MPLS Label DPOs
25 mpls_label_dpo_t *mpls_label_dpo_pool;
28 * Strings for the flags
30 const char* mpls_label_dpo_attr_names[] = MPLS_LABEL_DPO_ATTR_NAMES;
33 * registered DPO types for each of the label sub-types. And there's a
34 * subtype for each of the flag combinations.
36 static dpo_type_t mpls_label_dpo_types[1 << MPLS_LABEL_DPO_ATTR_MAX];
38 static mpls_label_dpo_t *
39 mpls_label_dpo_alloc (void)
41 mpls_label_dpo_t *mld;
43 pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
44 clib_memset(mld, 0, sizeof(*mld));
46 dpo_reset(&mld->mld_dpo);
52 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
54 return (mld - mpls_label_dpo_pool);
58 mpls_label_dpo_create (fib_mpls_label_t *label_stack,
60 dpo_proto_t payload_proto,
61 mpls_label_dpo_flags_t flags,
62 const dpo_id_t *parent,
65 mpls_label_dpo_t *mld;
69 if ((DPO_PROTO_IP4 != payload_proto) &&
70 (DPO_PROTO_IP6 != payload_proto))
73 * remove unsupported configuration
75 flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
78 mld = mpls_label_dpo_alloc();
79 mld->mld_flags = flags;
80 dtype = mpls_label_dpo_types[flags];
82 if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
84 clib_warning("Label stack size exceeded");
86 mld->mld_payload_proto,
88 drop_dpo_get(DPO_PROTO_MPLS));
92 mld->mld_n_labels = vec_len(label_stack);
93 mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
94 mld->mld_payload_proto = payload_proto;
97 * construct label rewrite headers for each value passed.
98 * get the header in network byte order since we will paint it
99 * on a packet in the data-plane
101 for (ii = 0; ii < mld->mld_n_labels-1; ii++)
103 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
104 label_stack[ii].fml_value);
105 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
106 label_stack[ii].fml_exp);
107 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
109 if (0 != label_stack[ii].fml_ttl)
111 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
112 label_stack[ii].fml_ttl);
116 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
117 MPLS_LABEL_DEFAULT_TTL);
119 mld->mld_hdr[ii].label_exp_s_ttl =
120 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
124 * the inner most label
126 ii = mld->mld_n_labels-1;
128 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
129 label_stack[ii].fml_value);
130 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
131 label_stack[ii].fml_exp);
132 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
133 if (0 != label_stack[ii].fml_ttl)
135 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
136 label_stack[ii].fml_ttl);
140 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
141 MPLS_LABEL_DEFAULT_TTL);
143 mld->mld_hdr[ii].label_exp_s_ttl =
144 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
147 * pipe/uniform mode is only supported for the bottom of stack label
149 if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
151 mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
155 mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
157 dtype = mpls_label_dpo_types[mld->mld_flags];
160 * stack this label object on its parent.
163 mld->mld_payload_proto,
170 mld->mld_payload_proto,
171 mpls_label_dpo_get_index(mld));
175 format_mpls_label_dpo_flags (u8 *s, va_list *args)
177 mpls_label_dpo_flags_t flags = va_arg (*args, int);
178 mpls_label_dpo_attr_t attr;
180 FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
182 if ((1 << attr) & flags)
184 s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
192 format_mpls_label_dpo (u8 *s, va_list *args)
194 index_t index = va_arg (*args, index_t);
195 u32 indent = va_arg (*args, u32);
196 mpls_unicast_header_t hdr;
197 mpls_label_dpo_t *mld;
200 if (pool_is_free_index(mpls_label_dpo_pool, index))
203 * the packet trace can be printed after the DPO has been deleted
205 return (format(s, "mpls-label[???,%d]:", index));
208 mld = mpls_label_dpo_get(index);
209 s = format(s, "mpls-label[%U@%d]:",
210 format_mpls_label_dpo_flags,
211 (int) mld->mld_flags, index);
213 for (ii = 0; ii < mld->mld_n_labels; ii++)
215 hdr.label_exp_s_ttl =
216 clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
217 s = format(s, "%U", format_mpls_header, hdr);
220 s = format(s, "\n%U", format_white_space, indent);
221 s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
227 mpls_label_dpo_lock (dpo_id_t *dpo)
229 mpls_label_dpo_t *mld;
231 mld = mpls_label_dpo_get(dpo->dpoi_index);
237 mpls_label_dpo_unlock (dpo_id_t *dpo)
239 mpls_label_dpo_t *mld;
241 mld = mpls_label_dpo_get(dpo->dpoi_index);
245 if (0 == mld->mld_locks)
247 dpo_reset(&mld->mld_dpo);
248 pool_put(mpls_label_dpo_pool, mld);
251 #endif /* CLIB_MARCH_VARIANT */
254 * @brief A struct to hold tracing information for the MPLS label imposition
257 typedef struct mpls_label_imposition_trace_t_
260 * The MPLS header imposed
262 mpls_unicast_header_t hdr;
265 * TTL imposed - only valid for uniform LSPs
270 * TTL imposed - only valid for uniform LSPs
273 } mpls_label_imposition_trace_t;
275 always_inline mpls_unicast_header_t *
276 mpls_label_paint (vlib_buffer_t * b0,
277 mpls_label_dpo_t *mld0)
279 mpls_unicast_header_t *hdr0;
281 vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
283 hdr0 = vlib_buffer_get_current(b0);
285 if (1 == mld0->mld_n_labels)
287 /* optimise for the common case of one label */
288 *hdr0 = mld0->mld_hdr[0];
292 clib_memcpy_fast(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
293 hdr0 = hdr0 + (mld0->mld_n_labels - 1);
300 * Paint on an MPLS label and fixup the TTL
302 always_inline mpls_unicast_header_t *
303 mpls_label_paint_w_ttl (vlib_buffer_t * b0,
304 mpls_label_dpo_t *mld0,
307 mpls_unicast_header_t *hdr0;
309 hdr0 = mpls_label_paint(b0, mld0);
311 /* fixup the TTL for the inner most label */
312 ((char*)hdr0)[3] = ttl0;
318 * Paint on an MPLS label and fixup the TTL and EXP bits.
320 always_inline mpls_unicast_header_t *
321 mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0,
322 mpls_label_dpo_t *mld0,
326 mpls_unicast_header_t *hdr0;
328 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
330 /* fixup the EXP for the inner most label */
331 ((char*)hdr0)[2] |= (exp0 << 1);
337 * Paint on an MPLS label and fixup the TTL and EXP bits
338 * When the EXP bits are *already* bit shift to the correct place in
339 * in the 2nd byte (i.e. they were read from another label)
341 always_inline mpls_unicast_header_t *
342 mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0,
343 mpls_label_dpo_t *mld0,
347 mpls_unicast_header_t *hdr0;
349 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
351 /* fixup the EXP for the inner most label */
352 ((char*)hdr0)[2] |= exp0;
358 mpls_label_imposition_inline (vlib_main_t * vm,
359 vlib_node_runtime_t * node,
360 vlib_frame_t * from_frame,
361 const dpo_proto_t dproto,
362 const mpls_label_dpo_flags_t flags)
364 u32 n_left_from, next_index, * from, * to_next;
366 from = vlib_frame_vector_args (from_frame);
367 n_left_from = from_frame->n_vectors;
369 next_index = node->cached_next_index;
371 while (n_left_from > 0)
375 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
377 while (n_left_from >= 8 && n_left_to_next >= 4)
379 u32 bi0, mldi0, bi1, mldi1, bi2, mldi2, bi3, mldi3;
380 mpls_unicast_header_t *hdr0, *hdr1, *hdr2, *hdr3;
381 mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3;
382 vlib_buffer_t * b0, *b1, * b2, *b3;
383 u32 next0, next1, next2, next3;
384 u8 ttl0, ttl1, ttl2, ttl3;
385 u8 exp0, exp1, exp2, exp3;
387 bi0 = to_next[0] = from[0];
388 bi1 = to_next[1] = from[1];
389 bi2 = to_next[2] = from[2];
390 bi3 = to_next[3] = from[3];
392 /* Prefetch next iteration. */
394 vlib_buffer_t * p2, * p3, *p4, *p5;
396 p2 = vlib_get_buffer (vm, from[2]);
397 p3 = vlib_get_buffer (vm, from[3]);
398 p4 = vlib_get_buffer (vm, from[4]);
399 p5 = vlib_get_buffer (vm, from[5]);
401 vlib_prefetch_buffer_header (p2, STORE);
402 vlib_prefetch_buffer_header (p3, STORE);
403 vlib_prefetch_buffer_header (p4, STORE);
404 vlib_prefetch_buffer_header (p5, STORE);
406 CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
407 CLIB_PREFETCH (p3->data, sizeof (hdr0[0]), STORE);
408 CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
409 CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
417 b0 = vlib_get_buffer (vm, bi0);
418 b1 = vlib_get_buffer (vm, bi1);
419 b2 = vlib_get_buffer (vm, bi2);
420 b3 = vlib_get_buffer (vm, bi3);
422 /* dst lookup was done by ip4 lookup */
423 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
424 mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
425 mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
426 mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
427 mld0 = mpls_label_dpo_get(mldi0);
428 mld1 = mpls_label_dpo_get(mldi1);
429 mld2 = mpls_label_dpo_get(mldi2);
430 mld3 = mpls_label_dpo_get(mldi3);
432 if (DPO_PROTO_MPLS != dproto)
435 * These are the non-MPLS payload imposition cases
437 if (DPO_PROTO_IP4 == dproto)
439 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
440 ip4_header_t * ip1 = vlib_buffer_get_current(b1);
441 ip4_header_t * ip2 = vlib_buffer_get_current(b2);
442 ip4_header_t * ip3 = vlib_buffer_get_current(b3);
444 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
447 * decrement the TTL on ingress to the LSP
454 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
455 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
456 checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
457 checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
459 checksum0 += checksum0 >= 0xffff;
460 checksum1 += checksum1 >= 0xffff;
461 checksum2 += checksum2 >= 0xffff;
462 checksum3 += checksum3 >= 0xffff;
464 ip0->checksum = checksum0;
465 ip1->checksum = checksum1;
466 ip2->checksum = checksum2;
467 ip3->checksum = checksum3;
475 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
481 /* by default copy the 3 most significant bits */
482 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
483 exp1 = ip_dscp_to_mpls_exp(ip1->tos);
484 exp2 = ip_dscp_to_mpls_exp(ip2->tos);
485 exp3 = ip_dscp_to_mpls_exp(ip3->tos);
488 else if (DPO_PROTO_IP6 == dproto)
491 * decrement the TTL on ingress to the LSP
493 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
494 ip6_header_t * ip1 = vlib_buffer_get_current(b1);
495 ip6_header_t * ip2 = vlib_buffer_get_current(b2);
496 ip6_header_t * ip3 = vlib_buffer_get_current(b3);
498 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
505 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
507 ttl0 = ip0->hop_limit;
508 ttl1 = ip1->hop_limit;
509 ttl2 = ip2->hop_limit;
510 ttl3 = ip3->hop_limit;
511 /* by default copy the 3 most significant bits */
512 exp0 = ip_dscp_to_mpls_exp(
513 ip6_traffic_class_network_order(ip0));
514 exp1 = ip_dscp_to_mpls_exp(
515 ip6_traffic_class_network_order(ip1));
516 exp2 = ip_dscp_to_mpls_exp(
517 ip6_traffic_class_network_order(ip2));
518 exp3 = ip_dscp_to_mpls_exp(
519 ip6_traffic_class_network_order(ip3));
525 * nothing to change in the ethernet header
527 ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
528 exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
531 * These are the non-MPLS payload imposition cases.
532 * Based on the LSP mode either, for uniform, copy down the TTL
533 * and EXP from the payload or, for pipe mode, slap on the value
534 * requested from config
536 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
538 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
539 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
540 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
541 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
545 hdr0 = mpls_label_paint(b0, mld0);
546 hdr1 = mpls_label_paint(b1, mld1);
547 hdr2 = mpls_label_paint(b2, mld2);
548 hdr3 = mpls_label_paint(b3, mld3);
554 * else, the packet to be encapped is an MPLS packet
555 * there are two cases to consider:
556 * 1 - this is an MPLS label swap at an LSP midpoint.
557 * recognisable because mpls.first = 1. In this case the
558 * TTL must be set to the current value -1.
559 * 2 - The MPLS packet is recursing (or being injected into)
560 * this LSP, in which case the pipe/uniform rules apply
563 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
566 * The first label to be imposed on the packet. this is a
567 * label swap.in which case we stashed the TTL and EXP bits
568 * in the packet in the lookup node
570 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
572 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
573 exp0 = vnet_buffer(b0)->mpls.exp;
574 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
579 * not the first label. implying we are recusring down a
580 * chain of output labels. Each layer is considered a new
581 * LSP - hence the TTL/EXP are pipe/uniform handled
583 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
585 hdr0 = vlib_buffer_get_current(b0);
586 ttl0 = ((u8*)hdr0)[3];
587 exp0 = ((u8*)hdr0)[2] & 0xe;
588 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
592 hdr0 = mpls_label_paint(b0, mld0);
595 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
597 ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
599 ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
600 exp1 = vnet_buffer(b1)->mpls.exp;
601 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
605 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
607 hdr1 = vlib_buffer_get_current(b1);
608 ttl1 = ((u8*)hdr1)[3];
609 exp1 = ((u8*)hdr1)[2] & 0xe;
610 hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
614 hdr1 = mpls_label_paint(b1, mld1);
617 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
619 ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
621 ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
622 exp2 = vnet_buffer(b2)->mpls.exp;
623 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
627 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
629 hdr2 = vlib_buffer_get_current(b2);
630 ttl2 = ((u8*)hdr2)[3];
631 exp2 = ((u8*)hdr2)[2] & 0xe;
632 hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
636 hdr2 = mpls_label_paint(b2, mld2);
639 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
641 ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
643 ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
644 exp3 = vnet_buffer(b3)->mpls.exp;
645 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
649 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
651 hdr3 = vlib_buffer_get_current(b3);
652 ttl3 = ((u8*)hdr3)[3];
653 exp3 = ((u8*)hdr3)[2] & 0xe;
654 hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
658 hdr3 = mpls_label_paint(b3, mld3);
662 vnet_buffer(b0)->mpls.first = 0;
663 vnet_buffer(b1)->mpls.first = 0;
664 vnet_buffer(b2)->mpls.first = 0;
665 vnet_buffer(b3)->mpls.first = 0;
668 next0 = mld0->mld_dpo.dpoi_next_node;
669 next1 = mld1->mld_dpo.dpoi_next_node;
670 next2 = mld2->mld_dpo.dpoi_next_node;
671 next3 = mld3->mld_dpo.dpoi_next_node;
673 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
674 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
675 vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
676 vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
678 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
680 mpls_label_imposition_trace_t *tr =
681 vlib_add_trace (vm, node, b0, sizeof (*tr));
683 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
690 tr->ttl = tr->exp = 0;
693 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
695 mpls_label_imposition_trace_t *tr =
696 vlib_add_trace (vm, node, b1, sizeof (*tr));
698 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
705 tr->ttl = tr->exp = 0;
708 if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
710 mpls_label_imposition_trace_t *tr =
711 vlib_add_trace (vm, node, b2, sizeof (*tr));
713 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
720 tr->ttl = tr->exp = 0;
723 if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
725 mpls_label_imposition_trace_t *tr =
726 vlib_add_trace (vm, node, b3, sizeof (*tr));
728 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
735 tr->ttl = tr->exp = 0;
739 vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
742 next0, next1, next2, next3);
745 while (n_left_from > 0 && n_left_to_next > 0)
747 mpls_unicast_header_t *hdr0;
748 mpls_label_dpo_t *mld0;
761 b0 = vlib_get_buffer (vm, bi0);
763 /* dst lookup was done by ip4 lookup */
764 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
765 mld0 = mpls_label_dpo_get(mldi0);
767 if (DPO_PROTO_MPLS != dproto)
769 if (DPO_PROTO_IP4 == dproto)
772 * decrement the TTL on ingress to the LSP
774 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
775 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
779 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
780 checksum0 += checksum0 >= 0xffff;
782 ip0->checksum = checksum0;
785 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
788 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
791 else if (DPO_PROTO_IP6 == dproto)
794 * decrement the TTL on ingress to the LSP
796 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
798 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
802 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
804 ttl0 = ip0->hop_limit;
805 exp0 = ip_dscp_to_mpls_exp(
806 ip6_traffic_class_network_order(ip0));
812 * nothing to change in the ethernet header
814 ttl0 = MPLS_LABEL_DEFAULT_TTL;
815 exp0 = MPLS_LABEL_DEFAULT_EXP;
819 * These are the non-MPLS payload imposition cases.
820 * Based on the LSP mode either, for uniform, copy down the TTL
821 * from the payload or, for pipe mode, slap on the value
822 * requested from config
824 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
826 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
830 hdr0 = mpls_label_paint(b0, mld0);
835 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
837 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
839 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
840 exp0 = vnet_buffer(b0)->mpls.exp;
841 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
845 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
847 hdr0 = vlib_buffer_get_current(b0);
848 ttl0 = ((u8*)hdr0)[3];
849 exp0 = ((u8*)hdr0)[2] & 0xe;
850 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
854 hdr0 = mpls_label_paint(b0, mld0);
858 vnet_buffer(b0)->mpls.first = 0;
861 next0 = mld0->mld_dpo.dpoi_next_node;
862 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
864 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
866 mpls_label_imposition_trace_t *tr =
867 vlib_add_trace (vm, node, b0, sizeof (*tr));
869 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
876 tr->ttl = tr->exp = 0;
880 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
881 n_left_to_next, bi0, next0);
883 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
885 return from_frame->n_vectors;
889 format_mpls_label_imposition_trace (u8 * s, va_list * args)
891 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
892 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
893 mpls_label_imposition_trace_t * t;
894 mpls_unicast_header_t hdr;
897 t = va_arg (*args, mpls_label_imposition_trace_t *);
898 indent = format_get_indent (s);
899 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
901 s = format (s, "%Umpls-header:%U",
902 format_white_space, indent,
903 format_mpls_header, hdr);
907 VLIB_NODE_FN (mpls_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
908 vlib_node_runtime_t * node,
909 vlib_frame_t * frame)
911 return (mpls_label_imposition_inline(vm, node, frame,
913 MPLS_LABEL_DPO_FLAG_NONE));
916 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = {
917 .name = "mpls-label-imposition-pipe",
918 .vector_size = sizeof (u32),
920 .format_trace = format_mpls_label_imposition_trace,
927 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
928 vlib_node_runtime_t * node,
929 vlib_frame_t * frame)
931 return (mpls_label_imposition_inline(vm, node, frame,
933 MPLS_LABEL_DPO_FLAG_NONE));
936 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
937 .name = "ip4-mpls-label-imposition-pipe",
938 .vector_size = sizeof (u32),
940 .format_trace = format_mpls_label_imposition_trace,
947 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
948 vlib_node_runtime_t * node,
949 vlib_frame_t * frame)
951 return (mpls_label_imposition_inline(vm, node, frame,
953 MPLS_LABEL_DPO_FLAG_NONE));
956 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
957 .name = "ip6-mpls-label-imposition-pipe",
958 .vector_size = sizeof (u32),
960 .format_trace = format_mpls_label_imposition_trace,
967 VLIB_NODE_FN (ethernet_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
968 vlib_node_runtime_t * node,
969 vlib_frame_t * frame)
971 return (mpls_label_imposition_inline(vm, node, frame,
973 MPLS_LABEL_DPO_FLAG_NONE));
976 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
977 .name = "ethernet-mpls-label-imposition-pipe",
978 .vector_size = sizeof (u32),
980 .format_trace = format_mpls_label_imposition_trace,
987 VLIB_NODE_FN (mpls_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
988 vlib_node_runtime_t * node,
989 vlib_frame_t * frame)
991 return (mpls_label_imposition_inline(vm, node, frame,
993 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
996 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
997 .name = "mpls-label-imposition-uniform",
998 .vector_size = sizeof (u32),
1000 .format_trace = format_mpls_label_imposition_trace,
1007 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1008 vlib_node_runtime_t * node,
1009 vlib_frame_t * frame)
1011 return (mpls_label_imposition_inline(vm, node, frame,
1013 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1016 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = {
1017 .name = "ip4-mpls-label-imposition-uniform",
1018 .vector_size = sizeof (u32),
1020 .format_trace = format_mpls_label_imposition_trace,
1027 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1028 vlib_node_runtime_t * node,
1029 vlib_frame_t * frame)
1031 return (mpls_label_imposition_inline(vm, node, frame,
1033 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1036 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1037 .name = "ip6-mpls-label-imposition-uniform",
1038 .vector_size = sizeof (u32),
1040 .format_trace = format_mpls_label_imposition_trace,
1047 VLIB_NODE_FN (ethernet_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1048 vlib_node_runtime_t * node,
1049 vlib_frame_t * frame)
1051 return (mpls_label_imposition_inline(vm, node, frame,
1053 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1056 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1057 .name = "ethernet-mpls-label-imposition-uniform",
1058 .vector_size = sizeof (u32),
1060 .format_trace = format_mpls_label_imposition_trace,
1068 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1069 vlib_node_runtime_t * node,
1070 vlib_frame_t * frame)
1072 return (mpls_label_imposition_inline(vm, node, frame,
1074 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1077 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1078 .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1079 .vector_size = sizeof (u32),
1081 .format_trace = format_mpls_label_imposition_trace,
1088 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1089 vlib_node_runtime_t * node,
1090 vlib_frame_t * frame)
1092 return (mpls_label_imposition_inline(vm, node, frame,
1094 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1097 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1098 .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1099 .vector_size = sizeof (u32),
1101 .format_trace = format_mpls_label_imposition_trace,
1108 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1109 vlib_node_runtime_t * node,
1110 vlib_frame_t * frame)
1112 return (mpls_label_imposition_inline(vm, node, frame,
1114 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1115 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1118 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1119 .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1120 .vector_size = sizeof (u32),
1122 .format_trace = format_mpls_label_imposition_trace,
1129 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1130 vlib_node_runtime_t * node,
1131 vlib_frame_t * frame)
1133 return (mpls_label_imposition_inline(vm, node, frame,
1135 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1136 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1139 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1140 .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1141 .vector_size = sizeof (u32),
1143 .format_trace = format_mpls_label_imposition_trace,
1151 #ifndef CLIB_MARCH_VARIANT
1153 mpls_label_dpo_mem_show (void)
1155 fib_show_memory_usage("MPLS label",
1156 pool_elts(mpls_label_dpo_pool),
1157 pool_len(mpls_label_dpo_pool),
1158 sizeof(mpls_label_dpo_t));
1162 * Interpose a label DPO. used in the FIB unit tests
1165 mpls_label_interpose (const dpo_id_t *original,
1166 const dpo_id_t *parent,
1169 mpls_label_dpo_t *mld, *mld_clone;
1171 mld_clone = mpls_label_dpo_alloc();
1172 mld = mpls_label_dpo_get(original->dpoi_index);
1174 mld_clone->mld_locks = 0;
1175 clib_memcpy_fast(&mld_clone->mld_hdr,
1177 sizeof(mld_clone->mld_hdr));
1178 mld_clone->mld_payload_proto = mld->mld_payload_proto;
1179 mld_clone->mld_n_labels = mld->mld_n_labels;
1180 mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1182 dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1183 mld_clone->mld_payload_proto,
1184 &mld_clone->mld_dpo,
1188 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1189 mld_clone->mld_payload_proto,
1190 mpls_label_dpo_get_index(mld_clone));
1193 const static dpo_vft_t mld_vft = {
1194 .dv_lock = mpls_label_dpo_lock,
1195 .dv_unlock = mpls_label_dpo_unlock,
1196 .dv_format = format_mpls_label_dpo,
1197 .dv_mem_show = mpls_label_dpo_mem_show,
1198 .dv_mk_interpose = mpls_label_interpose,
1201 const static char* const mpls_label_imp_pipe_ip4_nodes[] =
1203 "ip4-mpls-label-imposition-pipe",
1206 const static char* const mpls_label_imp_pipe_ip6_nodes[] =
1208 "ip6-mpls-label-imposition-pipe",
1211 const static char* const mpls_label_imp_pipe_mpls_nodes[] =
1213 "mpls-label-imposition-pipe",
1216 const static char* const mpls_label_imp_pipe_ethernet_nodes[] =
1218 "ethernet-mpls-label-imposition-pipe",
1222 const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] =
1224 [DPO_PROTO_IP4] = mpls_label_imp_pipe_ip4_nodes,
1225 [DPO_PROTO_IP6] = mpls_label_imp_pipe_ip6_nodes,
1226 [DPO_PROTO_MPLS] = mpls_label_imp_pipe_mpls_nodes,
1227 [DPO_PROTO_ETHERNET] = mpls_label_imp_pipe_ethernet_nodes,
1230 const static char* const mpls_label_imp_uniform_ip4_nodes[] =
1232 "ip4-mpls-label-imposition-uniform",
1235 const static char* const mpls_label_imp_uniform_ip6_nodes[] =
1237 "ip6-mpls-label-imposition-uniform",
1240 const static char* const mpls_label_imp_uniform_mpls_nodes[] =
1242 "mpls-label-imposition-uniform",
1245 const static char* const mpls_label_imp_uniform_ethernet_nodes[] =
1247 "ethernet-mpls-label-imposition-uniform",
1251 const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] =
1253 [DPO_PROTO_IP4] = mpls_label_imp_uniform_ip4_nodes,
1254 [DPO_PROTO_IP6] = mpls_label_imp_uniform_ip6_nodes,
1255 [DPO_PROTO_MPLS] = mpls_label_imp_uniform_mpls_nodes,
1256 [DPO_PROTO_ETHERNET] = mpls_label_imp_uniform_ethernet_nodes,
1259 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] =
1261 "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1264 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] =
1266 "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1270 const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1272 [DPO_PROTO_IP4] = mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes,
1273 [DPO_PROTO_IP6] = mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes,
1276 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] =
1278 "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1281 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] =
1283 "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1287 const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1289 [DPO_PROTO_IP4] = mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes,
1290 [DPO_PROTO_IP6] = mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes,
1294 mpls_label_dpo_module_init (void)
1296 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] =
1297 dpo_register_new_type(&mld_vft,
1298 mpls_label_imp_pipe_nodes);
1299 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1300 dpo_register_new_type(&mld_vft,
1301 mpls_label_imp_pipe_no_ip_tll_decr_nodes);
1302 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] =
1303 dpo_register_new_type(&mld_vft,
1304 mpls_label_imp_uniform_nodes);
1305 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1306 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1307 dpo_register_new_type(&mld_vft,
1308 mpls_label_imp_uniform_no_ip_tll_decr_nodes);
1312 mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1314 return (mpls_label_dpo_types[flags]);
1316 #endif /* CLIB_MARCH_VARIANT */