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;
45 dpo_pool_barrier_sync (vm, mpls_label_dpo_pool, did_barrier_sync);
46 pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
47 dpo_pool_barrier_release (vm, did_barrier_sync);
49 clib_memset(mld, 0, sizeof(*mld));
51 dpo_reset(&mld->mld_dpo);
57 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
59 return (mld - mpls_label_dpo_pool);
63 mpls_label_dpo_create (fib_mpls_label_t *label_stack,
65 dpo_proto_t payload_proto,
66 mpls_label_dpo_flags_t flags,
67 const dpo_id_t *parent,
70 mpls_label_dpo_t *mld;
74 if ((DPO_PROTO_IP4 != payload_proto) &&
75 (DPO_PROTO_IP6 != payload_proto))
78 * remove unsupported configuration
80 flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
83 mld = mpls_label_dpo_alloc();
84 mld->mld_flags = flags;
85 dtype = mpls_label_dpo_types[flags];
87 if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
89 clib_warning("Label stack size exceeded");
91 mld->mld_payload_proto,
93 drop_dpo_get(DPO_PROTO_MPLS));
97 mld->mld_n_labels = vec_len(label_stack);
98 mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
99 mld->mld_payload_proto = payload_proto;
102 * construct label rewrite headers for each value passed.
103 * get the header in network byte order since we will paint it
104 * on a packet in the data-plane
106 for (ii = 0; ii < mld->mld_n_labels-1; ii++)
108 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
109 label_stack[ii].fml_value);
110 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
111 label_stack[ii].fml_exp);
112 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
114 if (0 != label_stack[ii].fml_ttl)
116 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
117 label_stack[ii].fml_ttl);
121 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
122 MPLS_LABEL_DEFAULT_TTL);
124 mld->mld_hdr[ii].label_exp_s_ttl =
125 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
129 * the inner most label
131 ii = mld->mld_n_labels-1;
133 vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
134 label_stack[ii].fml_value);
135 vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
136 label_stack[ii].fml_exp);
137 vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
138 if (0 != label_stack[ii].fml_ttl)
140 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
141 label_stack[ii].fml_ttl);
145 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
146 MPLS_LABEL_DEFAULT_TTL);
148 mld->mld_hdr[ii].label_exp_s_ttl =
149 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
152 * pipe/uniform mode is only supported for the bottom of stack label
154 if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
156 mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
160 mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
162 dtype = mpls_label_dpo_types[mld->mld_flags];
165 * stack this label object on its parent.
168 mld->mld_payload_proto,
175 mld->mld_payload_proto,
176 mpls_label_dpo_get_index(mld));
180 format_mpls_label_dpo_flags (u8 *s, va_list *args)
182 mpls_label_dpo_flags_t flags = va_arg (*args, int);
183 mpls_label_dpo_attr_t attr;
185 FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
187 if ((1 << attr) & flags)
189 s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
197 format_mpls_label_dpo (u8 *s, va_list *args)
199 index_t index = va_arg (*args, index_t);
200 u32 indent = va_arg (*args, u32);
201 mpls_unicast_header_t hdr;
202 mpls_label_dpo_t *mld;
205 if (pool_is_free_index(mpls_label_dpo_pool, index))
208 * the packet trace can be printed after the DPO has been deleted
210 return (format(s, "mpls-label[???,%d]:", index));
213 mld = mpls_label_dpo_get(index);
214 s = format(s, "mpls-label[%U@%d]:",
215 format_mpls_label_dpo_flags,
216 (int) mld->mld_flags, index);
218 for (ii = 0; ii < mld->mld_n_labels; ii++)
220 hdr.label_exp_s_ttl =
221 clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
222 s = format(s, "%U", format_mpls_header, hdr);
225 s = format(s, "\n%U", format_white_space, indent);
226 s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
232 mpls_label_dpo_lock (dpo_id_t *dpo)
234 mpls_label_dpo_t *mld;
236 mld = mpls_label_dpo_get(dpo->dpoi_index);
242 mpls_label_dpo_unlock (dpo_id_t *dpo)
244 mpls_label_dpo_t *mld;
246 mld = mpls_label_dpo_get(dpo->dpoi_index);
250 if (0 == mld->mld_locks)
252 dpo_reset(&mld->mld_dpo);
253 pool_put(mpls_label_dpo_pool, mld);
256 #endif /* CLIB_MARCH_VARIANT */
259 * @brief A struct to hold tracing information for the MPLS label imposition
262 typedef struct mpls_label_imposition_trace_t_
265 * The MPLS header imposed
267 mpls_unicast_header_t hdr;
270 * TTL imposed - only valid for uniform LSPs
275 * TTL imposed - only valid for uniform LSPs
278 } mpls_label_imposition_trace_t;
280 always_inline mpls_unicast_header_t *
281 mpls_label_paint (vlib_buffer_t * b0,
282 mpls_label_dpo_t *mld0)
284 mpls_unicast_header_t *hdr0;
286 vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
288 hdr0 = vlib_buffer_get_current(b0);
290 if (1 == mld0->mld_n_labels)
292 /* optimise for the common case of one label */
293 *hdr0 = mld0->mld_hdr[0];
297 clib_memcpy_fast(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
298 hdr0 = hdr0 + (mld0->mld_n_labels - 1);
305 * Paint on an MPLS label and fixup the TTL
307 always_inline mpls_unicast_header_t *
308 mpls_label_paint_w_ttl (vlib_buffer_t * b0,
309 mpls_label_dpo_t *mld0,
312 mpls_unicast_header_t *hdr0;
314 hdr0 = mpls_label_paint(b0, mld0);
316 /* fixup the TTL for the inner most label */
317 ((char*)hdr0)[3] = ttl0;
323 * Paint on an MPLS label and fixup the TTL and EXP bits.
325 always_inline mpls_unicast_header_t *
326 mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0,
327 mpls_label_dpo_t *mld0,
331 mpls_unicast_header_t *hdr0;
333 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
335 /* fixup the EXP for the inner most label */
336 ((char*)hdr0)[2] |= (exp0 << 1);
342 * Paint on an MPLS label and fixup the TTL and EXP bits
343 * When the EXP bits are *already* bit shift to the correct place in
344 * in the 2nd byte (i.e. they were read from another label)
346 always_inline mpls_unicast_header_t *
347 mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0,
348 mpls_label_dpo_t *mld0,
352 mpls_unicast_header_t *hdr0;
354 hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
356 /* fixup the EXP for the inner most label */
357 ((char*)hdr0)[2] |= exp0;
363 mpls_label_imposition_inline (vlib_main_t * vm,
364 vlib_node_runtime_t * node,
365 vlib_frame_t * from_frame,
366 const dpo_proto_t dproto,
367 const mpls_label_dpo_flags_t flags)
369 u32 n_left_from, next_index, * from, * to_next;
371 from = vlib_frame_vector_args (from_frame);
372 n_left_from = from_frame->n_vectors;
374 next_index = node->cached_next_index;
376 while (n_left_from > 0)
380 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
382 while (n_left_from >= 8 && n_left_to_next >= 4)
384 u32 bi0, mldi0, bi1, mldi1, bi2, mldi2, bi3, mldi3;
385 mpls_unicast_header_t *hdr0, *hdr1, *hdr2, *hdr3;
386 mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3;
387 vlib_buffer_t * b0, *b1, * b2, *b3;
388 u32 next0, next1, next2, next3;
389 u8 ttl0, ttl1, ttl2, ttl3;
390 u8 exp0, exp1, exp2, exp3;
392 bi0 = to_next[0] = from[0];
393 bi1 = to_next[1] = from[1];
394 bi2 = to_next[2] = from[2];
395 bi3 = to_next[3] = from[3];
397 /* Prefetch next iteration. */
399 vlib_buffer_t * p2, * p3, *p4, *p5;
401 p2 = vlib_get_buffer (vm, from[2]);
402 p3 = vlib_get_buffer (vm, from[3]);
403 p4 = vlib_get_buffer (vm, from[4]);
404 p5 = vlib_get_buffer (vm, from[5]);
406 vlib_prefetch_buffer_header (p2, STORE);
407 vlib_prefetch_buffer_header (p3, STORE);
408 vlib_prefetch_buffer_header (p4, STORE);
409 vlib_prefetch_buffer_header (p5, STORE);
411 CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
412 CLIB_PREFETCH (p3->data, sizeof (hdr0[0]), STORE);
413 CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
414 CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
422 b0 = vlib_get_buffer (vm, bi0);
423 b1 = vlib_get_buffer (vm, bi1);
424 b2 = vlib_get_buffer (vm, bi2);
425 b3 = vlib_get_buffer (vm, bi3);
427 /* dst lookup was done by ip4 lookup */
428 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
429 mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
430 mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
431 mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
432 mld0 = mpls_label_dpo_get(mldi0);
433 mld1 = mpls_label_dpo_get(mldi1);
434 mld2 = mpls_label_dpo_get(mldi2);
435 mld3 = mpls_label_dpo_get(mldi3);
437 if (DPO_PROTO_MPLS != dproto)
440 * These are the non-MPLS payload imposition cases
442 if (DPO_PROTO_IP4 == dproto)
444 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
445 ip4_header_t * ip1 = vlib_buffer_get_current(b1);
446 ip4_header_t * ip2 = vlib_buffer_get_current(b2);
447 ip4_header_t * ip3 = vlib_buffer_get_current(b3);
449 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
452 * decrement the TTL on ingress to the LSP
459 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
460 checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
461 checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
462 checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
464 checksum0 += checksum0 >= 0xffff;
465 checksum1 += checksum1 >= 0xffff;
466 checksum2 += checksum2 >= 0xffff;
467 checksum3 += checksum3 >= 0xffff;
469 ip0->checksum = checksum0;
470 ip1->checksum = checksum1;
471 ip2->checksum = checksum2;
472 ip3->checksum = checksum3;
480 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
486 /* by default copy the 3 most significant bits */
487 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
488 exp1 = ip_dscp_to_mpls_exp(ip1->tos);
489 exp2 = ip_dscp_to_mpls_exp(ip2->tos);
490 exp3 = ip_dscp_to_mpls_exp(ip3->tos);
493 /* save the payload proto information in mpls opaque */
494 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
495 vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP4;
496 vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP4;
497 vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP4;
499 else if (DPO_PROTO_IP6 == dproto)
502 * decrement the TTL on ingress to the LSP
504 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
505 ip6_header_t * ip1 = vlib_buffer_get_current(b1);
506 ip6_header_t * ip2 = vlib_buffer_get_current(b2);
507 ip6_header_t * ip3 = vlib_buffer_get_current(b3);
509 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
516 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
518 ttl0 = ip0->hop_limit;
519 ttl1 = ip1->hop_limit;
520 ttl2 = ip2->hop_limit;
521 ttl3 = ip3->hop_limit;
522 /* by default copy the 3 most significant bits */
523 exp0 = ip_dscp_to_mpls_exp(
524 ip6_traffic_class_network_order(ip0));
525 exp1 = ip_dscp_to_mpls_exp(
526 ip6_traffic_class_network_order(ip1));
527 exp2 = ip_dscp_to_mpls_exp(
528 ip6_traffic_class_network_order(ip2));
529 exp3 = ip_dscp_to_mpls_exp(
530 ip6_traffic_class_network_order(ip3));
533 /* save the payload proto information in mpls opaque */
534 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
535 vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP6;
536 vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP6;
537 vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP6;
542 * nothing to change in the ethernet header
544 ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
545 exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
548 * These are the non-MPLS payload imposition cases.
549 * Based on the LSP mode either, for uniform, copy down the TTL
550 * and EXP from the payload or, for pipe mode, slap on the value
551 * requested from config
553 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
555 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
556 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
557 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
558 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
562 hdr0 = mpls_label_paint(b0, mld0);
563 hdr1 = mpls_label_paint(b1, mld1);
564 hdr2 = mpls_label_paint(b2, mld2);
565 hdr3 = mpls_label_paint(b3, mld3);
571 * else, the packet to be encapped is an MPLS packet
572 * there are two cases to consider:
573 * 1 - this is an MPLS label swap at an LSP midpoint.
574 * recognisable because mpls.first = 1. In this case the
575 * TTL must be set to the current value -1.
576 * 2 - The MPLS packet is recursing (or being injected into)
577 * this LSP, in which case the pipe/uniform rules apply
580 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
583 * The first label to be imposed on the packet. this is a
584 * label swap.in which case we stashed the TTL and EXP bits
585 * in the packet in the lookup node
587 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
589 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
590 exp0 = vnet_buffer(b0)->mpls.exp;
591 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
596 * not the first label. implying we are recusring down a
597 * chain of output labels. Each layer is considered a new
598 * LSP - hence the TTL/EXP are pipe/uniform handled
600 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
602 hdr0 = vlib_buffer_get_current(b0);
603 ttl0 = ((u8*)hdr0)[3];
604 exp0 = ((u8*)hdr0)[2] & 0xe;
605 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
609 hdr0 = mpls_label_paint(b0, mld0);
612 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
614 ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
616 ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
617 exp1 = vnet_buffer(b1)->mpls.exp;
618 hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
622 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
624 hdr1 = vlib_buffer_get_current(b1);
625 ttl1 = ((u8*)hdr1)[3];
626 exp1 = ((u8*)hdr1)[2] & 0xe;
627 hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
631 hdr1 = mpls_label_paint(b1, mld1);
634 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
636 ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
638 ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
639 exp2 = vnet_buffer(b2)->mpls.exp;
640 hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
644 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
646 hdr2 = vlib_buffer_get_current(b2);
647 ttl2 = ((u8*)hdr2)[3];
648 exp2 = ((u8*)hdr2)[2] & 0xe;
649 hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
653 hdr2 = mpls_label_paint(b2, mld2);
656 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
658 ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
660 ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
661 exp3 = vnet_buffer(b3)->mpls.exp;
662 hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
666 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
668 hdr3 = vlib_buffer_get_current(b3);
669 ttl3 = ((u8*)hdr3)[3];
670 exp3 = ((u8*)hdr3)[2] & 0xe;
671 hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
675 hdr3 = mpls_label_paint(b3, mld3);
679 vnet_buffer(b0)->mpls.first = 0;
680 vnet_buffer(b1)->mpls.first = 0;
681 vnet_buffer(b2)->mpls.first = 0;
682 vnet_buffer(b3)->mpls.first = 0;
685 next0 = mld0->mld_dpo.dpoi_next_node;
686 next1 = mld1->mld_dpo.dpoi_next_node;
687 next2 = mld2->mld_dpo.dpoi_next_node;
688 next3 = mld3->mld_dpo.dpoi_next_node;
690 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
691 vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
692 vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
693 vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
695 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
697 mpls_label_imposition_trace_t *tr =
698 vlib_add_trace (vm, node, b0, sizeof (*tr));
700 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
707 tr->ttl = tr->exp = 0;
710 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
712 mpls_label_imposition_trace_t *tr =
713 vlib_add_trace (vm, node, b1, sizeof (*tr));
715 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
722 tr->ttl = tr->exp = 0;
725 if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
727 mpls_label_imposition_trace_t *tr =
728 vlib_add_trace (vm, node, b2, sizeof (*tr));
730 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
737 tr->ttl = tr->exp = 0;
740 if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
742 mpls_label_imposition_trace_t *tr =
743 vlib_add_trace (vm, node, b3, sizeof (*tr));
745 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
752 tr->ttl = tr->exp = 0;
756 vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
759 next0, next1, next2, next3);
762 while (n_left_from > 0 && n_left_to_next > 0)
764 mpls_unicast_header_t *hdr0;
765 mpls_label_dpo_t *mld0;
778 b0 = vlib_get_buffer (vm, bi0);
780 /* dst lookup was done by ip4 lookup */
781 mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
782 mld0 = mpls_label_dpo_get(mldi0);
784 if (DPO_PROTO_MPLS != dproto)
786 if (DPO_PROTO_IP4 == dproto)
789 * decrement the TTL on ingress to the LSP
791 ip4_header_t * ip0 = vlib_buffer_get_current(b0);
792 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
796 checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
797 checksum0 += checksum0 >= 0xffff;
799 ip0->checksum = checksum0;
802 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
805 exp0 = ip_dscp_to_mpls_exp(ip0->tos);
808 /* save the payload proto information in mpls opaque */
809 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
811 else if (DPO_PROTO_IP6 == dproto)
814 * decrement the TTL on ingress to the LSP
816 ip6_header_t * ip0 = vlib_buffer_get_current(b0);
818 if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
822 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
824 ttl0 = ip0->hop_limit;
825 exp0 = ip_dscp_to_mpls_exp(
826 ip6_traffic_class_network_order(ip0));
829 /* save the payload proto information in mpls opaque */
830 vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
835 * nothing to change in the ethernet header
837 ttl0 = MPLS_LABEL_DEFAULT_TTL;
838 exp0 = MPLS_LABEL_DEFAULT_EXP;
842 * These are the non-MPLS payload imposition cases.
843 * Based on the LSP mode either, for uniform, copy down the TTL
844 * from the payload or, for pipe mode, slap on the value
845 * requested from config
847 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
849 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
853 hdr0 = mpls_label_paint(b0, mld0);
858 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
860 ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
862 ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
863 exp0 = vnet_buffer(b0)->mpls.exp;
864 hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
868 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
870 hdr0 = vlib_buffer_get_current(b0);
871 ttl0 = ((u8*)hdr0)[3];
872 exp0 = ((u8*)hdr0)[2] & 0xe;
873 hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
877 hdr0 = mpls_label_paint(b0, mld0);
881 vnet_buffer(b0)->mpls.first = 0;
884 next0 = mld0->mld_dpo.dpoi_next_node;
885 vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
887 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
889 mpls_label_imposition_trace_t *tr =
890 vlib_add_trace (vm, node, b0, sizeof (*tr));
892 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
899 tr->ttl = tr->exp = 0;
903 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
904 n_left_to_next, bi0, next0);
906 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
908 return from_frame->n_vectors;
912 format_mpls_label_imposition_trace (u8 * s, va_list * args)
914 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
915 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
916 mpls_label_imposition_trace_t * t;
917 mpls_unicast_header_t hdr;
920 t = va_arg (*args, mpls_label_imposition_trace_t *);
921 indent = format_get_indent (s);
922 hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
924 s = format (s, "%Umpls-header:%U",
925 format_white_space, indent,
926 format_mpls_header, hdr);
930 VLIB_NODE_FN (mpls_mpls_label_imposition_pipe_node) (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 (mpls_mpls_label_imposition_pipe_node) = {
940 .name = "mpls-label-imposition-pipe",
941 .vector_size = sizeof (u32),
943 .format_trace = format_mpls_label_imposition_trace,
950 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
951 vlib_node_runtime_t * node,
952 vlib_frame_t * frame)
954 return (mpls_label_imposition_inline(vm, node, frame,
956 MPLS_LABEL_DPO_FLAG_NONE));
959 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
960 .name = "ip4-mpls-label-imposition-pipe",
961 .vector_size = sizeof (u32),
963 .format_trace = format_mpls_label_imposition_trace,
970 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
971 vlib_node_runtime_t * node,
972 vlib_frame_t * frame)
974 return (mpls_label_imposition_inline(vm, node, frame,
976 MPLS_LABEL_DPO_FLAG_NONE));
979 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
980 .name = "ip6-mpls-label-imposition-pipe",
981 .vector_size = sizeof (u32),
983 .format_trace = format_mpls_label_imposition_trace,
990 VLIB_NODE_FN (ethernet_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
991 vlib_node_runtime_t * node,
992 vlib_frame_t * frame)
994 return (mpls_label_imposition_inline(vm, node, frame,
996 MPLS_LABEL_DPO_FLAG_NONE));
999 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
1000 .name = "ethernet-mpls-label-imposition-pipe",
1001 .vector_size = sizeof (u32),
1003 .format_trace = format_mpls_label_imposition_trace,
1010 VLIB_NODE_FN (mpls_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1011 vlib_node_runtime_t * node,
1012 vlib_frame_t * frame)
1014 return (mpls_label_imposition_inline(vm, node, frame,
1016 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1019 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
1020 .name = "mpls-label-imposition-uniform",
1021 .vector_size = sizeof (u32),
1023 .format_trace = format_mpls_label_imposition_trace,
1030 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1031 vlib_node_runtime_t * node,
1032 vlib_frame_t * frame)
1034 return (mpls_label_imposition_inline(vm, node, frame,
1036 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1039 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = {
1040 .name = "ip4-mpls-label-imposition-uniform",
1041 .vector_size = sizeof (u32),
1043 .format_trace = format_mpls_label_imposition_trace,
1050 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1051 vlib_node_runtime_t * node,
1052 vlib_frame_t * frame)
1054 return (mpls_label_imposition_inline(vm, node, frame,
1056 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1059 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1060 .name = "ip6-mpls-label-imposition-uniform",
1061 .vector_size = sizeof (u32),
1063 .format_trace = format_mpls_label_imposition_trace,
1070 VLIB_NODE_FN (ethernet_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1071 vlib_node_runtime_t * node,
1072 vlib_frame_t * frame)
1074 return (mpls_label_imposition_inline(vm, node, frame,
1076 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1079 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1080 .name = "ethernet-mpls-label-imposition-uniform",
1081 .vector_size = sizeof (u32),
1083 .format_trace = format_mpls_label_imposition_trace,
1091 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1092 vlib_node_runtime_t * node,
1093 vlib_frame_t * frame)
1095 return (mpls_label_imposition_inline(vm, node, frame,
1097 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1100 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1101 .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1102 .vector_size = sizeof (u32),
1104 .format_trace = format_mpls_label_imposition_trace,
1111 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1112 vlib_node_runtime_t * node,
1113 vlib_frame_t * frame)
1115 return (mpls_label_imposition_inline(vm, node, frame,
1117 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1120 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1121 .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1122 .vector_size = sizeof (u32),
1124 .format_trace = format_mpls_label_imposition_trace,
1131 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1132 vlib_node_runtime_t * node,
1133 vlib_frame_t * frame)
1135 return (mpls_label_imposition_inline(vm, node, frame,
1137 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1138 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1141 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1142 .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1143 .vector_size = sizeof (u32),
1145 .format_trace = format_mpls_label_imposition_trace,
1152 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1153 vlib_node_runtime_t * node,
1154 vlib_frame_t * frame)
1156 return (mpls_label_imposition_inline(vm, node, frame,
1158 (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1159 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1162 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1163 .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1164 .vector_size = sizeof (u32),
1166 .format_trace = format_mpls_label_imposition_trace,
1174 #ifndef CLIB_MARCH_VARIANT
1176 mpls_label_dpo_mem_show (void)
1178 fib_show_memory_usage("MPLS label",
1179 pool_elts(mpls_label_dpo_pool),
1180 pool_len(mpls_label_dpo_pool),
1181 sizeof(mpls_label_dpo_t));
1185 * Interpose a label DPO. used in the FIB unit tests
1188 mpls_label_interpose (const dpo_id_t *original,
1189 const dpo_id_t *parent,
1192 mpls_label_dpo_t *mld, *mld_clone;
1194 mld_clone = mpls_label_dpo_alloc();
1195 mld = mpls_label_dpo_get(original->dpoi_index);
1197 mld_clone->mld_locks = 0;
1198 clib_memcpy_fast(&mld_clone->mld_hdr,
1200 sizeof(mld_clone->mld_hdr));
1201 mld_clone->mld_payload_proto = mld->mld_payload_proto;
1202 mld_clone->mld_n_labels = mld->mld_n_labels;
1203 mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1205 dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1206 mld_clone->mld_payload_proto,
1207 &mld_clone->mld_dpo,
1211 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1212 mld_clone->mld_payload_proto,
1213 mpls_label_dpo_get_index(mld_clone));
1216 const static dpo_vft_t mld_vft = {
1217 .dv_lock = mpls_label_dpo_lock,
1218 .dv_unlock = mpls_label_dpo_unlock,
1219 .dv_format = format_mpls_label_dpo,
1220 .dv_mem_show = mpls_label_dpo_mem_show,
1221 .dv_mk_interpose = mpls_label_interpose,
1224 const static char* const mpls_label_imp_pipe_ip4_nodes[] =
1226 "ip4-mpls-label-imposition-pipe",
1229 const static char* const mpls_label_imp_pipe_ip6_nodes[] =
1231 "ip6-mpls-label-imposition-pipe",
1234 const static char* const mpls_label_imp_pipe_mpls_nodes[] =
1236 "mpls-label-imposition-pipe",
1239 const static char* const mpls_label_imp_pipe_ethernet_nodes[] =
1241 "ethernet-mpls-label-imposition-pipe",
1245 const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] =
1247 [DPO_PROTO_IP4] = mpls_label_imp_pipe_ip4_nodes,
1248 [DPO_PROTO_IP6] = mpls_label_imp_pipe_ip6_nodes,
1249 [DPO_PROTO_MPLS] = mpls_label_imp_pipe_mpls_nodes,
1250 [DPO_PROTO_ETHERNET] = mpls_label_imp_pipe_ethernet_nodes,
1253 const static char* const mpls_label_imp_uniform_ip4_nodes[] =
1255 "ip4-mpls-label-imposition-uniform",
1258 const static char* const mpls_label_imp_uniform_ip6_nodes[] =
1260 "ip6-mpls-label-imposition-uniform",
1263 const static char* const mpls_label_imp_uniform_mpls_nodes[] =
1265 "mpls-label-imposition-uniform",
1268 const static char* const mpls_label_imp_uniform_ethernet_nodes[] =
1270 "ethernet-mpls-label-imposition-uniform",
1274 const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] =
1276 [DPO_PROTO_IP4] = mpls_label_imp_uniform_ip4_nodes,
1277 [DPO_PROTO_IP6] = mpls_label_imp_uniform_ip6_nodes,
1278 [DPO_PROTO_MPLS] = mpls_label_imp_uniform_mpls_nodes,
1279 [DPO_PROTO_ETHERNET] = mpls_label_imp_uniform_ethernet_nodes,
1282 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] =
1284 "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1287 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] =
1289 "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1293 const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1295 [DPO_PROTO_IP4] = mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes,
1296 [DPO_PROTO_IP6] = mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes,
1299 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] =
1301 "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1304 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] =
1306 "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1310 const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1312 [DPO_PROTO_IP4] = mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes,
1313 [DPO_PROTO_IP6] = mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes,
1317 mpls_label_dpo_module_init (void)
1319 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] =
1320 dpo_register_new_type(&mld_vft,
1321 mpls_label_imp_pipe_nodes);
1322 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1323 dpo_register_new_type(&mld_vft,
1324 mpls_label_imp_pipe_no_ip_tll_decr_nodes);
1325 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] =
1326 dpo_register_new_type(&mld_vft,
1327 mpls_label_imp_uniform_nodes);
1328 mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1329 MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1330 dpo_register_new_type(&mld_vft,
1331 mpls_label_imp_uniform_no_ip_tll_decr_nodes);
1335 mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1337 return (mpls_label_dpo_types[flags]);
1339 #endif /* CLIB_MARCH_VARIANT */