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>
22 * pool of all MPLS Label DPOs
24 mpls_label_dpo_t *mpls_label_dpo_pool;
27 * Strings for the flags
29 const char* mpls_label_dpo_attr_names[] = MPLS_LABEL_DPO_ATTR_NAMES;
32 * registered DPO types for each of the label sub-types. And there's a
33 * subtype for each of the flag combinations.
35 static dpo_type_t mpls_label_dpo_types[1 << MPLS_LABEL_DPO_ATTR_MAX];
37 static mpls_label_dpo_t *
38 mpls_label_dpo_alloc (void)
40 mpls_label_dpo_t *mld;
42 pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
43 memset(mld, 0, sizeof(*mld));
45 dpo_reset(&mld->mld_dpo);
51 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
53 return (mld - mpls_label_dpo_pool);
57 mpls_label_dpo_create (fib_mpls_label_t *label_stack,
59 dpo_proto_t payload_proto,
60 mpls_label_dpo_flags_t flags,
61 const dpo_id_t *parent,
64 mpls_label_dpo_t *mld;
68 if ((DPO_PROTO_IP4 != payload_proto) &&
69 (DPO_PROTO_IP6 != payload_proto))
72 * remove unsupported configuration
74 flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
77 mld = mpls_label_dpo_alloc();
78 mld->mld_flags = flags;
79 dtype = mpls_label_dpo_types[flags];
81 if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
83 clib_warning("Label stack size exceeded");
85 mld->mld_payload_proto,
87 drop_dpo_get(DPO_PROTO_MPLS));
91 mld->mld_n_labels = vec_len(label_stack);
92 mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
93 mld->mld_payload_proto = payload_proto;
96 * construct label rewrite headers for each value passed.
97 * get the header in network byte order since we will paint it
98 * on a packet in the data-plane
100 for (ii = 0; ii < mld->mld_n_labels-1; ii++)
102 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
103 label_stack[ii].fml_value);
104 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
105 label_stack[ii].fml_exp);
106 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
108 if (0 != label_stack[ii].fml_ttl)
110 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
111 label_stack[ii].fml_ttl);
115 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
116 MPLS_LABEL_DEFAULT_TTL);
118 mld->mld_hdr[ii].label_exp_s_ttl =
119 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
123 * the inner most label
125 ii = mld->mld_n_labels-1;
127 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
128 label_stack[ii].fml_value);
129 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
130 label_stack[ii].fml_exp);
131 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
132 if (0 != label_stack[ii].fml_ttl)
134 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
135 label_stack[ii].fml_ttl);
139 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
140 MPLS_LABEL_DEFAULT_TTL);
142 mld->mld_hdr[ii].label_exp_s_ttl =
143 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
146 * pipe/uniform mode is only supported for the bottom of stack label
148 if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
150 mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
154 mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
156 dtype = mpls_label_dpo_types[mld->mld_flags];
159 * stack this label object on its parent.
162 mld->mld_payload_proto,
169 mld->mld_payload_proto,
170 mpls_label_dpo_get_index(mld));
174 format_mpls_label_dpo_flags (u8 *s, va_list *args)
176 mpls_label_dpo_flags_t flags = va_arg (*args, int);
177 mpls_label_dpo_attr_t attr;
179 FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
181 if ((1 << attr) & flags)
183 s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
191 format_mpls_label_dpo (u8 *s, va_list *args)
193 index_t index = va_arg (*args, index_t);
194 u32 indent = va_arg (*args, u32);
195 mpls_unicast_header_t hdr;
196 mpls_label_dpo_t *mld;
199 if (pool_is_free_index(mpls_label_dpo_pool, index))
202 * the packet trace can be printed after the DPO has been deleted
204 return (format(s, "mpls-label[???,%d]:", index));
207 mld = mpls_label_dpo_get(index);
208 s = format(s, "mpls-label[%U%d]:",
209 format_mpls_label_dpo_flags,
210 (int) mld->mld_flags, index);
212 for (ii = 0; ii < mld->mld_n_labels; ii++)
214 hdr.label_exp_s_ttl =
215 clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
216 s = format(s, "%U", format_mpls_header, hdr);
219 s = format(s, "\n%U", format_white_space, indent);
220 s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
226 mpls_label_dpo_lock (dpo_id_t *dpo)
228 mpls_label_dpo_t *mld;
230 mld = mpls_label_dpo_get(dpo->dpoi_index);
236 mpls_label_dpo_unlock (dpo_id_t *dpo)
238 mpls_label_dpo_t *mld;
240 mld = mpls_label_dpo_get(dpo->dpoi_index);
244 if (0 == mld->mld_locks)
246 dpo_reset(&mld->mld_dpo);
247 pool_put(mpls_label_dpo_pool, mld);
252 * @brief A struct to hold tracing information for the MPLS label imposition
255 typedef struct mpls_label_imposition_trace_t_
258 * The MPLS header imposed
260 mpls_unicast_header_t hdr;
263 * TTL imposed - only valid for uniform LSPs
268 * TTL imposed - only valid for uniform LSPs
271 } mpls_label_imposition_trace_t;
273 always_inline mpls_unicast_header_t *
274 mpls_label_paint (vlib_buffer_t * b0,
275 mpls_label_dpo_t *mld0)
277 mpls_unicast_header_t *hdr0;
279 vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
281 hdr0 = vlib_buffer_get_current(b0);
283 if (1 == mld0->mld_n_labels)
285 /* optimise for the common case of one label */
286 *hdr0 = mld0->mld_hdr[0];
290 clib_memcpy(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
291 hdr0 = hdr0 + (mld0->mld_n_labels - 1);
298 * Paint on an MPLS label and fixup the TTL
300 always_inline mpls_unicast_header_t *
301 mpls_label_paint_w_ttl (vlib_buffer_t * b0,
302 mpls_label_dpo_t *mld0,
305 mpls_unicast_header_t *hdr0;
307 hdr0 = mpls_label_paint(b0, mld0);
309 /* fixup the TTL for the inner most label */
310 ((char*)hdr0)[3] = ttl0;
316 * Paint on an MPLS label and fixup the TTL and EXP bits.
318 always_inline mpls_unicast_header_t *
319 mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0,
320 mpls_label_dpo_t *mld0,
324 mpls_unicast_header_t *hdr0;
326 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
328 /* fixup the EXP for the inner most label */
329 ((char*)hdr0)[2] |= (exp0 << 1);
335 * Paint on an MPLS label and fixup the TTL and EXP bits
336 * When the EXP bits are *already* bit shift to the correct place in
337 * in the 2nd byte (i.e. they were read from another label)
339 always_inline mpls_unicast_header_t *
340 mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0,
341 mpls_label_dpo_t *mld0,
345 mpls_unicast_header_t *hdr0;
347 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
349 /* fixup the EXP for the inner most label */
350 ((char*)hdr0)[2] |= exp0;
356 mpls_label_imposition_inline (vlib_main_t * vm,
357 vlib_node_runtime_t * node,
358 vlib_frame_t * from_frame,
359 const dpo_proto_t dproto,
360 const mpls_label_dpo_flags_t flags)
362 u32 n_left_from, next_index, * from, * to_next;
364 from = vlib_frame_vector_args (from_frame);
365 n_left_from = from_frame->n_vectors;
367 next_index = node->cached_next_index;
369 while (n_left_from > 0)
373 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
375 while (n_left_from >= 8 && n_left_to_next >= 4)
377 u32 bi0, mldi0, bi1, mldi1, bi2, mldi2, bi3, mldi3;
378 mpls_unicast_header_t *hdr0, *hdr1, *hdr2, *hdr3;
379 mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3;
380 vlib_buffer_t * b0, *b1, * b2, *b3;
381 u32 next0, next1, next2, next3;
382 u8 ttl0, ttl1, ttl2, ttl3;
383 u8 exp0, exp1, exp2, exp3;
385 bi0 = to_next[0] = from[0];
386 bi1 = to_next[1] = from[1];
387 bi2 = to_next[2] = from[2];
388 bi3 = to_next[3] = from[3];
390 /* Prefetch next iteration. */
392 vlib_buffer_t * p2, * p3, *p4, *p5;
394 p2 = vlib_get_buffer (vm, from[2]);
395 p3 = vlib_get_buffer (vm, from[3]);
396 p4 = vlib_get_buffer (vm, from[4]);
397 p5 = vlib_get_buffer (vm, from[5]);
399 vlib_prefetch_buffer_header (p2, STORE);
400 vlib_prefetch_buffer_header (p3, STORE);
401 vlib_prefetch_buffer_header (p4, STORE);
402 vlib_prefetch_buffer_header (p5, STORE);
404 CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
405 CLIB_PREFETCH (p3->data, sizeof (hdr0[0]), STORE);
406 CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
407 CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
415 b0 = vlib_get_buffer (vm, bi0);
416 b1 = vlib_get_buffer (vm, bi1);
417 b2 = vlib_get_buffer (vm, bi2);
418 b3 = vlib_get_buffer (vm, bi3);
420 /* dst lookup was done by ip4 lookup */
421 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
422 mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
423 mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
424 mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
425 mld0 = mpls_label_dpo_get(mldi0);
426 mld1 = mpls_label_dpo_get(mldi1);
427 mld2 = mpls_label_dpo_get(mldi2);
428 mld3 = mpls_label_dpo_get(mldi3);
430 if (DPO_PROTO_MPLS != dproto)
433 * These are the non-MPLS payload imposition cases
435 if (DPO_PROTO_IP4 == dproto)
437 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
438 ip4_header_t * ip1 = vlib_buffer_get_current(b1);
439 ip4_header_t * ip2 = vlib_buffer_get_current(b2);
440 ip4_header_t * ip3 = vlib_buffer_get_current(b3);
442 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
445 * decrement the TTL on ingress to the LSP
452 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
453 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
454 checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
455 checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
457 checksum0 += checksum0 >= 0xffff;
458 checksum1 += checksum1 >= 0xffff;
459 checksum2 += checksum2 >= 0xffff;
460 checksum3 += checksum3 >= 0xffff;
462 ip0->checksum = checksum0;
463 ip1->checksum = checksum1;
464 ip2->checksum = checksum2;
465 ip3->checksum = checksum3;
473 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
479 /* by default copy the 3 most significant bits */
480 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
481 exp1 = ip_dscp_to_mpls_exp(ip1->tos);
482 exp2 = ip_dscp_to_mpls_exp(ip2->tos);
483 exp3 = ip_dscp_to_mpls_exp(ip3->tos);
486 else if (DPO_PROTO_IP6 == dproto)
489 * decrement the TTL on ingress to the LSP
491 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
492 ip6_header_t * ip1 = vlib_buffer_get_current(b1);
493 ip6_header_t * ip2 = vlib_buffer_get_current(b2);
494 ip6_header_t * ip3 = vlib_buffer_get_current(b3);
496 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
503 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
505 ttl0 = ip0->hop_limit;
506 ttl1 = ip1->hop_limit;
507 ttl2 = ip2->hop_limit;
508 ttl3 = ip3->hop_limit;
509 /* by default copy the 3 most significant bits */
510 exp0 = ip_dscp_to_mpls_exp(
511 ip6_traffic_class_network_order(ip0));
512 exp1 = ip_dscp_to_mpls_exp(
513 ip6_traffic_class_network_order(ip1));
514 exp2 = ip_dscp_to_mpls_exp(
515 ip6_traffic_class_network_order(ip2));
516 exp3 = ip_dscp_to_mpls_exp(
517 ip6_traffic_class_network_order(ip3));
523 * nothing to change in the ethernet header
525 ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
526 exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
529 * These are the non-MPLS payload imposition cases.
530 * Based on the LSP mode either, for uniform, copy down the TTL
531 * and EXP from the payload or, for pipe mode, slap on the value
532 * requested from config
534 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
536 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
537 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
538 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
539 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
543 hdr0 = mpls_label_paint(b0, mld0);
544 hdr1 = mpls_label_paint(b1, mld1);
545 hdr2 = mpls_label_paint(b2, mld2);
546 hdr3 = mpls_label_paint(b3, mld3);
552 * else, the packet to be encapped is an MPLS packet
553 * there are two cases to consider:
554 * 1 - this is an MPLS label swap at an LSP midpoint.
555 * recognisable because mpls.first = 1. In this case the
556 * TTL must be set to the current value -1.
557 * 2 - The MPLS packet is recursing (or being injected into)
558 * this LSP, in which case the pipe/uniform rules apply
561 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
564 * The first label to be imposed on the packet. this is a
565 * label swap.in which case we stashed the TTL and EXP bits
566 * in the packet in the lookup node
568 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
570 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
571 exp0 = vnet_buffer(b0)->mpls.exp;
572 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
577 * not the first label. implying we are recusring down a
578 * chain of output labels. Each layer is considered a new
579 * LSP - hence the TTL/EXP are pipe/uniform handled
581 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
583 hdr0 = vlib_buffer_get_current(b0);
584 ttl0 = ((u8*)hdr0)[3];
585 exp0 = ((u8*)hdr0)[2] & 0xe;
586 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
590 hdr0 = mpls_label_paint(b0, mld0);
593 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
595 ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
597 ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
598 exp1 = vnet_buffer(b1)->mpls.exp;
599 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
603 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
605 hdr1 = vlib_buffer_get_current(b1);
606 ttl1 = ((u8*)hdr1)[3];
607 exp1 = ((u8*)hdr1)[2] & 0xe;
608 hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
612 hdr1 = mpls_label_paint(b1, mld1);
615 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
617 ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
619 ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
620 exp2 = vnet_buffer(b2)->mpls.exp;
621 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
625 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
627 hdr2 = vlib_buffer_get_current(b2);
628 ttl2 = ((u8*)hdr2)[3];
629 exp2 = ((u8*)hdr2)[2] & 0xe;
630 hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
634 hdr2 = mpls_label_paint(b2, mld2);
637 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
639 ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
641 ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
642 exp3 = vnet_buffer(b3)->mpls.exp;
643 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
647 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
649 hdr3 = vlib_buffer_get_current(b3);
650 ttl3 = ((u8*)hdr3)[3];
651 exp3 = ((u8*)hdr3)[2] & 0xe;
652 hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
656 hdr3 = mpls_label_paint(b3, mld3);
660 vnet_buffer(b0)->mpls.first = 0;
661 vnet_buffer(b1)->mpls.first = 0;
662 vnet_buffer(b2)->mpls.first = 0;
663 vnet_buffer(b3)->mpls.first = 0;
666 next0 = mld0->mld_dpo.dpoi_next_node;
667 next1 = mld1->mld_dpo.dpoi_next_node;
668 next2 = mld2->mld_dpo.dpoi_next_node;
669 next3 = mld3->mld_dpo.dpoi_next_node;
671 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
672 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
673 vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
674 vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
676 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
678 mpls_label_imposition_trace_t *tr =
679 vlib_add_trace (vm, node, b0, sizeof (*tr));
681 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
688 tr->ttl = tr->exp = 0;
691 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
693 mpls_label_imposition_trace_t *tr =
694 vlib_add_trace (vm, node, b1, sizeof (*tr));
696 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
703 tr->ttl = tr->exp = 0;
706 if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
708 mpls_label_imposition_trace_t *tr =
709 vlib_add_trace (vm, node, b2, sizeof (*tr));
711 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
718 tr->ttl = tr->exp = 0;
721 if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
723 mpls_label_imposition_trace_t *tr =
724 vlib_add_trace (vm, node, b3, sizeof (*tr));
726 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
733 tr->ttl = tr->exp = 0;
737 vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
740 next0, next1, next2, next3);
743 while (n_left_from > 0 && n_left_to_next > 0)
745 mpls_unicast_header_t *hdr0;
746 mpls_label_dpo_t *mld0;
759 b0 = vlib_get_buffer (vm, bi0);
761 /* dst lookup was done by ip4 lookup */
762 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
763 mld0 = mpls_label_dpo_get(mldi0);
765 if (DPO_PROTO_MPLS != dproto)
767 if (DPO_PROTO_IP4 == dproto)
770 * decrement the TTL on ingress to the LSP
772 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
773 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
777 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
778 checksum0 += checksum0 >= 0xffff;
780 ip0->checksum = checksum0;
783 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
786 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
789 else if (DPO_PROTO_IP6 == dproto)
792 * decrement the TTL on ingress to the LSP
794 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
796 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
800 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
802 ttl0 = ip0->hop_limit;
803 exp0 = ip_dscp_to_mpls_exp(
804 ip6_traffic_class_network_order(ip0));
810 * nothing to change in the ethernet header
812 ttl0 = MPLS_LABEL_DEFAULT_TTL;
813 exp0 = MPLS_LABEL_DEFAULT_EXP;
817 * These are the non-MPLS payload imposition cases.
818 * Based on the LSP mode either, for uniform, copy down the TTL
819 * from the payload or, for pipe mode, slap on the value
820 * requested from config
822 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
824 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
828 hdr0 = mpls_label_paint(b0, mld0);
833 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
835 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
837 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
838 exp0 = vnet_buffer(b0)->mpls.exp;
839 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
843 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
845 hdr0 = vlib_buffer_get_current(b0);
846 ttl0 = ((u8*)hdr0)[3];
847 exp0 = ((u8*)hdr0)[2] & 0xe;
848 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
852 hdr0 = mpls_label_paint(b0, mld0);
856 vnet_buffer(b0)->mpls.first = 0;
859 next0 = mld0->mld_dpo.dpoi_next_node;
860 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
862 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
864 mpls_label_imposition_trace_t *tr =
865 vlib_add_trace (vm, node, b0, sizeof (*tr));
867 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
874 tr->ttl = tr->exp = 0;
878 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
879 n_left_to_next, bi0, next0);
881 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
883 return from_frame->n_vectors;
887 format_mpls_label_imposition_trace (u8 * s, va_list * args)
889 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
890 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
891 mpls_label_imposition_trace_t * t;
892 mpls_unicast_header_t hdr;
895 t = va_arg (*args, mpls_label_imposition_trace_t *);
896 indent = format_get_indent (s);
897 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
899 s = format (s, "%Umpls-header:%U",
900 format_white_space, indent,
901 format_mpls_header, hdr);
906 mpls_mpls_label_imposition_pipe (vlib_main_t * vm,
907 vlib_node_runtime_t * node,
908 vlib_frame_t * frame)
910 return (mpls_label_imposition_inline(vm, node, frame,
912 MPLS_LABEL_DPO_FLAG_NONE));
915 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = {
916 .function = mpls_mpls_label_imposition_pipe,
917 .name = "mpls-label-imposition-pipe",
918 .vector_size = sizeof (u32),
920 .format_trace = format_mpls_label_imposition_trace,
926 VLIB_NODE_FUNCTION_MULTIARCH (mpls_mpls_label_imposition_pipe_node,
927 mpls_mpls_label_imposition_pipe)
930 ip4_mpls_label_imposition_pipe (vlib_main_t * vm,
931 vlib_node_runtime_t * node,
932 vlib_frame_t * frame)
934 return (mpls_label_imposition_inline(vm, node, frame,
936 MPLS_LABEL_DPO_FLAG_NONE));
939 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
940 .function = ip4_mpls_label_imposition_pipe,
941 .name = "ip4-mpls-label-imposition-pipe",
942 .vector_size = sizeof (u32),
944 .format_trace = format_mpls_label_imposition_trace,
950 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_pipe_node,
951 ip4_mpls_label_imposition_pipe)
954 ip6_mpls_label_imposition_pipe (vlib_main_t * vm,
955 vlib_node_runtime_t * node,
956 vlib_frame_t * frame)
958 return (mpls_label_imposition_inline(vm, node, frame,
960 MPLS_LABEL_DPO_FLAG_NONE));
963 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
964 .function = ip6_mpls_label_imposition_pipe,
965 .name = "ip6-mpls-label-imposition-pipe",
966 .vector_size = sizeof (u32),
968 .format_trace = format_mpls_label_imposition_trace,
974 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_pipe_node,
975 ip6_mpls_label_imposition_pipe)
978 ethernet_mpls_label_imposition_pipe (vlib_main_t * vm,
979 vlib_node_runtime_t * node,
980 vlib_frame_t * frame)
982 return (mpls_label_imposition_inline(vm, node, frame,
984 MPLS_LABEL_DPO_FLAG_NONE));
987 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
988 .function = ethernet_mpls_label_imposition_pipe,
989 .name = "ethernet-mpls-label-imposition-pipe",
990 .vector_size = sizeof (u32),
992 .format_trace = format_mpls_label_imposition_trace,
999 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_pipe_node,
1000 ethernet_mpls_label_imposition_pipe)
1003 mpls_mpls_label_imposition_uniform (vlib_main_t * vm,
1004 vlib_node_runtime_t * node,
1005 vlib_frame_t * frame)
1007 return (mpls_label_imposition_inline(vm, node, frame,
1009 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1012 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
1013 .function = mpls_mpls_label_imposition_uniform,
1014 .name = "mpls-label-imposition-uniform",
1015 .vector_size = sizeof (u32),
1017 .format_trace = format_mpls_label_imposition_trace,
1023 VLIB_NODE_FUNCTION_MULTIARCH (mpls_mpls_label_imposition_uniform_node,
1024 mpls_mpls_label_imposition_uniform)
1027 ip4_mpls_label_imposition_uniform (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 (ip4_mpls_label_imposition_uniform_node) = {
1037 .function = ip4_mpls_label_imposition_uniform,
1038 .name = "ip4-mpls-label-imposition-uniform",
1039 .vector_size = sizeof (u32),
1041 .format_trace = format_mpls_label_imposition_trace,
1047 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_uniform_node,
1048 ip4_mpls_label_imposition_uniform)
1051 ip6_mpls_label_imposition_uniform (vlib_main_t * vm,
1052 vlib_node_runtime_t * node,
1053 vlib_frame_t * frame)
1055 return (mpls_label_imposition_inline(vm, node, frame,
1057 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1060 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1061 .function = ip6_mpls_label_imposition_uniform,
1062 .name = "ip6-mpls-label-imposition-uniform",
1063 .vector_size = sizeof (u32),
1065 .format_trace = format_mpls_label_imposition_trace,
1071 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_uniform_node,
1072 ip6_mpls_label_imposition_uniform)
1075 ethernet_mpls_label_imposition_uniform (vlib_main_t * vm,
1076 vlib_node_runtime_t * node,
1077 vlib_frame_t * frame)
1079 return (mpls_label_imposition_inline(vm, node, frame,
1081 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1084 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1085 .function = ethernet_mpls_label_imposition_uniform,
1086 .name = "ethernet-mpls-label-imposition-uniform",
1087 .vector_size = sizeof (u32),
1089 .format_trace = format_mpls_label_imposition_trace,
1096 VLIB_NODE_FUNCTION_MULTIARCH (ethernet_mpls_label_imposition_uniform_node,
1097 ethernet_mpls_label_imposition_uniform)
1100 ip4_mpls_label_imposition_pipe_no_ip_ttl_decr (vlib_main_t * vm,
1101 vlib_node_runtime_t * node,
1102 vlib_frame_t * frame)
1104 return (mpls_label_imposition_inline(vm, node, frame,
1106 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1109 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1110 .function = ip4_mpls_label_imposition_pipe_no_ip_ttl_decr,
1111 .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1112 .vector_size = sizeof (u32),
1114 .format_trace = format_mpls_label_imposition_trace,
1120 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node,
1121 ip4_mpls_label_imposition_pipe_no_ip_ttl_decr)
1124 ip6_mpls_label_imposition_pipe_no_ip_ttl_decr (vlib_main_t * vm,
1125 vlib_node_runtime_t * node,
1126 vlib_frame_t * frame)
1128 return (mpls_label_imposition_inline(vm, node, frame,
1130 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1133 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1134 .function = ip6_mpls_label_imposition_pipe_no_ip_ttl_decr,
1135 .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1136 .vector_size = sizeof (u32),
1138 .format_trace = format_mpls_label_imposition_trace,
1144 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node,
1145 ip6_mpls_label_imposition_pipe_no_ip_ttl_decr)
1148 ip4_mpls_label_imposition_uniform_no_ip_ttl_decr (vlib_main_t * vm,
1149 vlib_node_runtime_t * node,
1150 vlib_frame_t * frame)
1152 return (mpls_label_imposition_inline(vm, node, frame,
1154 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1155 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1158 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1159 .function = ip4_mpls_label_imposition_uniform_no_ip_ttl_decr,
1160 .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1161 .vector_size = sizeof (u32),
1163 .format_trace = format_mpls_label_imposition_trace,
1169 VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node,
1170 ip4_mpls_label_imposition_uniform_no_ip_ttl_decr)
1173 ip6_mpls_label_imposition_uniform_no_ip_ttl_decr (vlib_main_t * vm,
1174 vlib_node_runtime_t * node,
1175 vlib_frame_t * frame)
1177 return (mpls_label_imposition_inline(vm, node, frame,
1179 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1180 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1183 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1184 .function = ip6_mpls_label_imposition_uniform_no_ip_ttl_decr,
1185 .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1186 .vector_size = sizeof (u32),
1188 .format_trace = format_mpls_label_imposition_trace,
1194 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node,
1195 ip6_mpls_label_imposition_uniform_no_ip_ttl_decr)
1199 mpls_label_dpo_mem_show (void)
1201 fib_show_memory_usage("MPLS label",
1202 pool_elts(mpls_label_dpo_pool),
1203 pool_len(mpls_label_dpo_pool),
1204 sizeof(mpls_label_dpo_t));
1208 * Interpose a label DPO. used in the FIB unit tests
1211 mpls_label_interpose (const dpo_id_t *original,
1212 const dpo_id_t *parent,
1215 mpls_label_dpo_t *mld, *mld_clone;
1217 mld_clone = mpls_label_dpo_alloc();
1218 mld = mpls_label_dpo_get(original->dpoi_index);
1220 mld_clone->mld_locks = 0;
1221 clib_memcpy(&mld_clone->mld_hdr,
1223 sizeof(mld_clone->mld_hdr));
1224 mld_clone->mld_payload_proto = mld->mld_payload_proto;
1225 mld_clone->mld_n_labels = mld->mld_n_labels;
1226 mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1228 dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1229 mld_clone->mld_payload_proto,
1230 &mld_clone->mld_dpo,
1234 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1235 mld_clone->mld_payload_proto,
1236 mpls_label_dpo_get_index(mld_clone));
1239 const static dpo_vft_t mld_vft = {
1240 .dv_lock = mpls_label_dpo_lock,
1241 .dv_unlock = mpls_label_dpo_unlock,
1242 .dv_format = format_mpls_label_dpo,
1243 .dv_mem_show = mpls_label_dpo_mem_show,
1244 .dv_mk_interpose = mpls_label_interpose,
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]);