ip: Path MTU
[vpp.git] / src / vnet / dpo / mpls_label_dpo.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
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>
20
21 // clang-format off
22
23 #ifndef CLIB_MARCH_VARIANT
24 /*
25  * pool of all MPLS Label DPOs
26  */
27 mpls_label_dpo_t *mpls_label_dpo_pool;
28
29 /**
30  * Strings for the flags
31  */
32 const char* mpls_label_dpo_attr_names[] = MPLS_LABEL_DPO_ATTR_NAMES;
33
34 /**
35  * registered DPO types for each of the label sub-types. And there's a
36  * subtype for each of the flag combinations.
37  */
38 static dpo_type_t mpls_label_dpo_types[1 << MPLS_LABEL_DPO_ATTR_MAX];
39
40 static mpls_label_dpo_t *
41 mpls_label_dpo_alloc (void)
42 {
43     mpls_label_dpo_t *mld;
44     vlib_main_t *vm;
45     u8 did_barrier_sync;
46
47     dpo_pool_barrier_sync (vm, mpls_label_dpo_pool, did_barrier_sync);
48     pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
49     dpo_pool_barrier_release (vm, did_barrier_sync);
50
51     clib_memset(mld, 0, sizeof(*mld));
52
53     dpo_reset(&mld->mld_dpo);
54
55     return (mld);
56 }
57
58 static index_t
59 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
60 {
61     return (mld - mpls_label_dpo_pool);
62 }
63
64 void
65 mpls_label_dpo_create (fib_mpls_label_t *label_stack,
66                        mpls_eos_bit_t eos,
67                        dpo_proto_t payload_proto,
68                        mpls_label_dpo_flags_t flags,
69                        const dpo_id_t *parent,
70                        dpo_id_t *dpo)
71 {
72     mpls_label_dpo_t *mld;
73     dpo_type_t dtype;
74     u32 ii;
75
76     if ((DPO_PROTO_IP4 != payload_proto) &&
77         (DPO_PROTO_IP6 != payload_proto))
78     {
79         /*
80          * remove unsupported configuration
81          */
82         flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
83     }
84
85     mld = mpls_label_dpo_alloc();
86     mld->mld_flags = flags;
87     dtype = mpls_label_dpo_types[flags];
88
89     if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
90     {
91         clib_warning("Label stack size exceeded");
92         dpo_stack(dtype,
93                   mld->mld_payload_proto,
94                   &mld->mld_dpo,
95                   drop_dpo_get(DPO_PROTO_MPLS));
96     }
97     else
98     {
99         mld->mld_n_labels = vec_len(label_stack);
100         mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
101         mld->mld_payload_proto = payload_proto;
102
103         /*
104          * construct label rewrite headers for each value passed.
105          * get the header in network byte order since we will paint it
106          * on a packet in the data-plane
107          */
108         for (ii = 0; ii < mld->mld_n_labels-1; ii++)
109         {
110             vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
111                                    label_stack[ii].fml_value);
112             vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
113                                  label_stack[ii].fml_exp);
114             vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
115                                MPLS_NON_EOS);
116             if (0 != label_stack[ii].fml_ttl)
117             {
118                 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
119                                      label_stack[ii].fml_ttl);
120             }
121             else
122             {
123                 vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
124                                      MPLS_LABEL_DEFAULT_TTL);
125             }
126             mld->mld_hdr[ii].label_exp_s_ttl =
127                 clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
128         }
129
130         /*
131          * the inner most label
132          */
133         ii = mld->mld_n_labels-1;
134
135         vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
136                                label_stack[ii].fml_value);
137         vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
138                              label_stack[ii].fml_exp);
139         vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
140         if (0 != label_stack[ii].fml_ttl)
141         {
142             vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
143                                  label_stack[ii].fml_ttl);
144         }
145         else
146         {
147             vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
148                                  MPLS_LABEL_DEFAULT_TTL);
149         }
150         mld->mld_hdr[ii].label_exp_s_ttl =
151             clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
152
153         /*
154          * pipe/uniform mode is only supported for the bottom of stack label
155          */
156         if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
157         {
158             mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
159         }
160         else
161         {
162             mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
163         }
164         dtype = mpls_label_dpo_types[mld->mld_flags];
165
166         /*
167          * stack this label object on its parent.
168          */
169         dpo_stack(dtype,
170                   mld->mld_payload_proto,
171                   &mld->mld_dpo,
172                   parent);
173     }
174
175     dpo_set(dpo,
176             dtype,
177             mld->mld_payload_proto,
178             mpls_label_dpo_get_index(mld));
179 }
180
181 u8*
182 format_mpls_label_dpo_flags (u8 *s, va_list *args)
183 {
184     mpls_label_dpo_flags_t flags = va_arg (*args, int);
185     mpls_label_dpo_attr_t attr;
186
187     FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
188     {
189         if ((1 << attr) & flags)
190         {
191             s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
192         }
193     }
194
195     return (s);
196 }
197
198 u8*
199 format_mpls_label_dpo (u8 *s, va_list *args)
200 {
201     index_t index = va_arg (*args, index_t);
202     u32 indent = va_arg (*args, u32);
203     mpls_unicast_header_t hdr;
204     mpls_label_dpo_t *mld;
205     u32 ii;
206
207     if (pool_is_free_index(mpls_label_dpo_pool, index))
208     {
209         /*
210          * the packet trace can be printed after the DPO has been deleted
211          */
212         return (format(s, "mpls-label[???,%d]:", index));
213     }
214
215     mld = mpls_label_dpo_get(index);
216     s = format(s, "mpls-label[%U@%d]:",
217                format_mpls_label_dpo_flags,
218                (int) mld->mld_flags, index);
219
220     for (ii = 0; ii < mld->mld_n_labels; ii++)
221     {
222         hdr.label_exp_s_ttl =
223             clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
224         s = format(s, "%U", format_mpls_header, hdr);
225     }
226
227     s = format(s, "\n%U", format_white_space, indent);
228     s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
229
230     return (s);
231 }
232
233 static void
234 mpls_label_dpo_lock (dpo_id_t *dpo)
235 {
236     mpls_label_dpo_t *mld;
237
238     mld = mpls_label_dpo_get(dpo->dpoi_index);
239
240     mld->mld_locks++;
241 }
242
243 static void
244 mpls_label_dpo_unlock (dpo_id_t *dpo)
245 {
246     mpls_label_dpo_t *mld;
247
248     mld = mpls_label_dpo_get(dpo->dpoi_index);
249
250     mld->mld_locks--;
251
252     if (0 == mld->mld_locks)
253     {
254         dpo_reset(&mld->mld_dpo);
255         pool_put(mpls_label_dpo_pool, mld);
256     }
257 }
258 #endif /* CLIB_MARCH_VARIANT */
259
260 /**
261  * @brief A struct to hold tracing information for the MPLS label imposition
262  * node.
263  */
264 typedef struct mpls_label_imposition_trace_t_
265 {
266     /**
267      * The MPLS header imposed
268      */
269     mpls_unicast_header_t hdr;
270
271     /**
272      * TTL imposed - only valid for uniform LSPs
273      */
274     u8 ttl;
275
276     /**
277      * TTL imposed - only valid for uniform LSPs
278      */
279     u8 exp;
280 } mpls_label_imposition_trace_t;
281
282 always_inline mpls_unicast_header_t *
283 mpls_label_paint (vlib_buffer_t * b0,
284                   mpls_label_dpo_t *mld0)
285 {
286     mpls_unicast_header_t *hdr0;
287
288     vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
289
290     hdr0 = vlib_buffer_get_current(b0);
291
292     if (1 == mld0->mld_n_labels)
293     {
294         /* optimise for the common case of one label */
295         *hdr0 = mld0->mld_hdr[0];
296     }
297     else
298     {
299         clib_memcpy_fast(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
300         hdr0 = hdr0 + (mld0->mld_n_labels - 1);
301     }
302
303     return (hdr0);
304 }
305
306 /**
307  * Paint on an MPLS label and fixup the TTL
308  */
309 always_inline mpls_unicast_header_t *
310 mpls_label_paint_w_ttl (vlib_buffer_t * b0,
311                         mpls_label_dpo_t *mld0,
312                         u8 ttl0)
313 {
314     mpls_unicast_header_t *hdr0;
315
316     hdr0 = mpls_label_paint(b0, mld0);
317
318     /* fixup the TTL for the inner most label */
319     ((char*)hdr0)[3] = ttl0;
320
321     return (hdr0);
322 }
323
324 /**
325  * Paint on an MPLS label and fixup the TTL and EXP bits.
326  */
327 always_inline mpls_unicast_header_t *
328 mpls_label_paint_w_ttl_exp (vlib_buffer_t * b0,
329                             mpls_label_dpo_t *mld0,
330                             u8 ttl0,
331                             u8 exp0)
332 {
333     mpls_unicast_header_t *hdr0;
334
335     hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
336
337     /* fixup the EXP for the inner most label */
338     ((char*)hdr0)[2] |= (exp0 << 1);
339
340     return (hdr0);
341 }
342
343 /**
344  * Paint on an MPLS label and fixup the TTL and EXP bits
345  * When the EXP bits are *already* bit shift to the correct place in
346  * in the 2nd byte (i.e. they were read from another label)
347  */
348 always_inline mpls_unicast_header_t *
349 mpls_label_paint_w_ttl_mpls_exp (vlib_buffer_t * b0,
350                                  mpls_label_dpo_t *mld0,
351                                  u8 ttl0,
352                                  u8 exp0)
353 {
354     mpls_unicast_header_t *hdr0;
355
356     hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
357
358     /* fixup the EXP for the inner most label */
359     ((char*)hdr0)[2] |= exp0;
360
361     return (hdr0);
362 }
363
364 always_inline uword
365 mpls_label_imposition_inline (vlib_main_t * vm,
366                               vlib_node_runtime_t * node,
367                               vlib_frame_t * from_frame,
368                               const dpo_proto_t dproto,
369                               const mpls_label_dpo_flags_t flags)
370 {
371     u32 n_left_from, next_index, * from, * to_next;
372
373     from = vlib_frame_vector_args (from_frame);
374     n_left_from = from_frame->n_vectors;
375
376     next_index = node->cached_next_index;
377
378     while (n_left_from > 0)
379     {
380         u32 n_left_to_next;
381
382         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
383
384         while (n_left_from >= 8 && n_left_to_next >= 4)
385         {
386             u32 bi0, mldi0, bi1, mldi1, bi2, mldi2, bi3, mldi3;
387             mpls_unicast_header_t *hdr0, *hdr1, *hdr2, *hdr3;
388             mpls_label_dpo_t *mld0, *mld1, *mld2, *mld3;
389             vlib_buffer_t * b0, *b1, * b2, *b3;
390             u32 next0, next1, next2, next3;
391             u8 ttl0, ttl1, ttl2, ttl3;
392             u8 exp0, exp1, exp2, exp3;
393
394             bi0 = to_next[0] = from[0];
395             bi1 = to_next[1] = from[1];
396             bi2 = to_next[2] = from[2];
397             bi3 = to_next[3] = from[3];
398
399             /* Prefetch next iteration. */
400             {
401                 vlib_buffer_t * p2, * p3, *p4, *p5;
402
403                 p2 = vlib_get_buffer (vm, from[2]);
404                 p3 = vlib_get_buffer (vm, from[3]);
405                 p4 = vlib_get_buffer (vm, from[4]);
406                 p5 = vlib_get_buffer (vm, from[5]);
407
408                 vlib_prefetch_buffer_header (p2, STORE);
409                 vlib_prefetch_buffer_header (p3, STORE);
410                 vlib_prefetch_buffer_header (p4, STORE);
411                 vlib_prefetch_buffer_header (p5, STORE);
412
413                 CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
414                 CLIB_PREFETCH (p3->data, sizeof (hdr0[0]), STORE);
415                 CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
416                 CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
417             }
418
419             from += 4;
420             to_next += 4;
421             n_left_from -= 4;
422             n_left_to_next -= 4;
423
424             b0 = vlib_get_buffer (vm, bi0);
425             b1 = vlib_get_buffer (vm, bi1);
426             b2 = vlib_get_buffer (vm, bi2);
427             b3 = vlib_get_buffer (vm, bi3);
428
429             /* dst lookup was done by ip4 lookup */
430             mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
431             mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
432             mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
433             mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
434             mld0 = mpls_label_dpo_get(mldi0);
435             mld1 = mpls_label_dpo_get(mldi1);
436             mld2 = mpls_label_dpo_get(mldi2);
437             mld3 = mpls_label_dpo_get(mldi3);
438
439             if (DPO_PROTO_MPLS != dproto)
440             {
441                 /*
442                  * These are the non-MPLS payload imposition cases
443                  */
444                 if (DPO_PROTO_IP4 == dproto)
445                 {
446                     ip4_header_t * ip0 = vlib_buffer_get_current(b0);
447                     ip4_header_t * ip1 = vlib_buffer_get_current(b1);
448                     ip4_header_t * ip2 = vlib_buffer_get_current(b2);
449                     ip4_header_t * ip3 = vlib_buffer_get_current(b3);
450
451                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
452                     {
453                         /*
454                          * decrement the TTL on ingress to the LSP
455                          */
456                         u32 checksum0;
457                         u32 checksum1;
458                         u32 checksum2;
459                         u32 checksum3;
460
461                         checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
462                         checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
463                         checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
464                         checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
465
466                         checksum0 += checksum0 >= 0xffff;
467                         checksum1 += checksum1 >= 0xffff;
468                         checksum2 += checksum2 >= 0xffff;
469                         checksum3 += checksum3 >= 0xffff;
470
471                         ip0->checksum = checksum0;
472                         ip1->checksum = checksum1;
473                         ip2->checksum = checksum2;
474                         ip3->checksum = checksum3;
475
476                         ip0->ttl -= 1;
477                         ip1->ttl -= 1;
478                         ip2->ttl -= 1;
479                         ip3->ttl -= 1;
480                     }
481
482                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
483                     {
484                         ttl1 = ip1->ttl;
485                         ttl0 = ip0->ttl;
486                         ttl3 = ip3->ttl;
487                         ttl2 = ip2->ttl;
488                         /* by default copy the 3 most significant bits */
489                         exp0 = ip_dscp_to_mpls_exp(ip0->tos);
490                         exp1 = ip_dscp_to_mpls_exp(ip1->tos);
491                         exp2 = ip_dscp_to_mpls_exp(ip2->tos);
492                         exp3 = ip_dscp_to_mpls_exp(ip3->tos);
493                     }
494
495                     /* save the payload proto information in mpls opaque */
496                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
497                     vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP4;
498                     vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP4;
499                     vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP4;
500                 }
501                 else if (DPO_PROTO_IP6 == dproto)
502                 {
503                     /*
504                      * decrement the TTL on ingress to the LSP
505                      */
506                     ip6_header_t * ip0 = vlib_buffer_get_current(b0);
507                     ip6_header_t * ip1 = vlib_buffer_get_current(b1);
508                     ip6_header_t * ip2 = vlib_buffer_get_current(b2);
509                     ip6_header_t * ip3 = vlib_buffer_get_current(b3);
510
511                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
512                     {
513                         ip0->hop_limit -= 1;
514                         ip1->hop_limit -= 1;
515                         ip2->hop_limit -= 1;
516                         ip3->hop_limit -= 1;
517                     }
518                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
519                     {
520                         ttl0 = ip0->hop_limit;
521                         ttl1 = ip1->hop_limit;
522                         ttl2 = ip2->hop_limit;
523                         ttl3 = ip3->hop_limit;
524                         /* by default copy the 3 most significant bits */
525                         exp0 = ip_dscp_to_mpls_exp(
526                             ip6_traffic_class_network_order(ip0));
527                         exp1 = ip_dscp_to_mpls_exp(
528                             ip6_traffic_class_network_order(ip1));
529                         exp2 = ip_dscp_to_mpls_exp(
530                             ip6_traffic_class_network_order(ip2));
531                         exp3 = ip_dscp_to_mpls_exp(
532                             ip6_traffic_class_network_order(ip3));
533                     }
534
535                     /* save the payload proto information in mpls opaque */
536                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
537                     vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP6;
538                     vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP6;
539                     vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP6;
540                 }
541                 else
542                 {
543                     /*
544                      * nothing to change in the ethernet header
545                      */
546                     ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
547                     exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
548                 }
549                 /*
550                  * These are the non-MPLS payload imposition cases.
551                  * Based on the LSP mode either, for uniform, copy down the TTL
552                  * and EXP from the payload or, for pipe mode, slap on the value
553                  * requested from config
554                  */
555                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
556                 {
557                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
558                     hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
559                     hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
560                     hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
561                 }
562                 else
563                 {
564                     hdr0 = mpls_label_paint(b0, mld0);
565                     hdr1 = mpls_label_paint(b1, mld1);
566                     hdr2 = mpls_label_paint(b2, mld2);
567                     hdr3 = mpls_label_paint(b3, mld3);
568                 }
569             }
570             else
571             {
572                 /*
573                  * else, the packet to be encapped is an MPLS packet
574                  * there are two cases to consider:
575                  *  1 - this is an MPLS label swap at an LSP midpoint.
576                  *      recognisable because mpls.first = 1. In this case the
577                  *      TTL must be set to the current value -1.
578                  *  2 - The MPLS packet is recursing (or being injected into)
579                  *      this LSP, in which case the pipe/uniform rules apply
580                  *
581                  */
582                 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
583                 {
584                     /*
585                      * The first label to be imposed on the packet. this is a
586                      * label swap.in which case we stashed the TTL and EXP bits
587                      * in the packet in the lookup node
588                      */
589                     ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
590
591                     ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
592                     exp0 = vnet_buffer(b0)->mpls.exp;
593                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
594                 }
595                 else
596                 {
597                     /*
598                      * not the first label. implying we are recusring down a
599                      * chain of output labels. Each layer is considered a new
600                      * LSP - hence the TTL/EXP are pipe/uniform handled
601                      */
602                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
603                     {
604                         hdr0 = vlib_buffer_get_current(b0);
605                         ttl0 = ((u8*)hdr0)[3];
606                         exp0 = ((u8*)hdr0)[2] & 0xe;
607                         hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
608                     }
609                     else
610                     {
611                         hdr0 = mpls_label_paint(b0, mld0);
612                     }
613                 }
614                 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
615                 {
616                     ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
617
618                     ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
619                     exp1 = vnet_buffer(b1)->mpls.exp;
620                     hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
621                 }
622                 else
623                 {
624                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
625                     {
626                         hdr1 = vlib_buffer_get_current(b1);
627                         ttl1 = ((u8*)hdr1)[3];
628                         exp1 = ((u8*)hdr1)[2] & 0xe;
629                         hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
630                     }
631                     else
632                     {
633                         hdr1 = mpls_label_paint(b1, mld1);
634                     }
635                 }
636                 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
637                 {
638                     ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
639
640                     ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
641                     exp2 = vnet_buffer(b2)->mpls.exp;
642                     hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
643                 }
644                 else
645                 {
646                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
647                     {
648                         hdr2 = vlib_buffer_get_current(b2);
649                         ttl2 = ((u8*)hdr2)[3];
650                         exp2 = ((u8*)hdr2)[2] & 0xe;
651                         hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
652                     }
653                     else
654                     {
655                         hdr2 = mpls_label_paint(b2, mld2);
656                     }
657                 }
658                 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
659                 {
660                     ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
661
662                     ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
663                     exp3 = vnet_buffer(b3)->mpls.exp;
664                     hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
665                 }
666                 else
667                 {
668                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
669                     {
670                         hdr3 = vlib_buffer_get_current(b3);
671                         ttl3 = ((u8*)hdr3)[3];
672                         exp3 = ((u8*)hdr3)[2] & 0xe;
673                         hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
674                     }
675                     else
676                     {
677                         hdr3 = mpls_label_paint(b3, mld3);
678                     }
679                 }
680
681                 vnet_buffer(b0)->mpls.first = 0;
682                 vnet_buffer(b1)->mpls.first = 0;
683                 vnet_buffer(b2)->mpls.first = 0;
684                 vnet_buffer(b3)->mpls.first = 0;
685             }
686
687             next0 = mld0->mld_dpo.dpoi_next_node;
688             next1 = mld1->mld_dpo.dpoi_next_node;
689             next2 = mld2->mld_dpo.dpoi_next_node;
690             next3 = mld3->mld_dpo.dpoi_next_node;
691
692             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
693             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
694             vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
695             vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
696
697             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
698             {
699                 mpls_label_imposition_trace_t *tr =
700                     vlib_add_trace (vm, node, b0, sizeof (*tr));
701                 tr->hdr = *hdr0;
702                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
703                 {
704                     tr->ttl = ttl0;
705                     tr->exp = exp0;
706                 }
707                 else
708                 {
709                     tr->ttl = tr->exp = 0;
710                 }
711             }
712             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
713             {
714                 mpls_label_imposition_trace_t *tr =
715                     vlib_add_trace (vm, node, b1, sizeof (*tr));
716                 tr->hdr = *hdr1;
717                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
718                 {
719                     tr->ttl = ttl1;
720                     tr->exp = exp1;
721                 }
722                 else
723                 {
724                     tr->ttl = tr->exp = 0;
725                 }
726             }
727             if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
728             {
729                 mpls_label_imposition_trace_t *tr =
730                     vlib_add_trace (vm, node, b2, sizeof (*tr));
731                 tr->hdr = *hdr2;
732                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
733                 {
734                     tr->ttl = ttl2;
735                     tr->exp = exp2;
736                 }
737                 else
738                 {
739                     tr->ttl = tr->exp = 0;
740                 }
741             }
742             if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
743             {
744                 mpls_label_imposition_trace_t *tr =
745                     vlib_add_trace (vm, node, b3, sizeof (*tr));
746                 tr->hdr = *hdr3;
747                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
748                 {
749                     tr->ttl = ttl3;
750                     tr->exp = exp3;
751                 }
752                 else
753                 {
754                     tr->ttl = tr->exp = 0;
755                 }
756             }
757
758             vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
759                                             n_left_to_next,
760                                             bi0, bi1, bi2, bi3,
761                                             next0, next1, next2, next3);
762         }
763
764         while (n_left_from > 0 && n_left_to_next > 0)
765         {
766             mpls_unicast_header_t *hdr0;
767             mpls_label_dpo_t *mld0;
768             vlib_buffer_t * b0;
769             u32 bi0, mldi0;
770             u8 ttl0, exp0;
771             u32 next0;
772
773             bi0 = from[0];
774             to_next[0] = bi0;
775             from += 1;
776             to_next += 1;
777             n_left_from -= 1;
778             n_left_to_next -= 1;
779
780             b0 = vlib_get_buffer (vm, bi0);
781
782             /* dst lookup was done by ip4 lookup */
783             mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
784             mld0 = mpls_label_dpo_get(mldi0);
785
786             if (DPO_PROTO_MPLS != dproto)
787             {
788                 if (DPO_PROTO_IP4 == dproto)
789                 {
790                     /*
791                      * decrement the TTL on ingress to the LSP
792                      */
793                     ip4_header_t * ip0 = vlib_buffer_get_current(b0);
794                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
795                     {
796                         u32 checksum0;
797
798                         checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
799                         checksum0 += checksum0 >= 0xffff;
800
801                         ip0->checksum = checksum0;
802                         ip0->ttl -= 1;
803                     }
804                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
805                     {
806                         ttl0 = ip0->ttl;
807                         exp0 = ip_dscp_to_mpls_exp(ip0->tos);
808                     }
809
810                     /* save the payload proto information in mpls opaque */
811                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
812                 }
813                 else if (DPO_PROTO_IP6 == dproto)
814                 {
815                     /*
816                      * decrement the TTL on ingress to the LSP
817                      */
818                     ip6_header_t * ip0 = vlib_buffer_get_current(b0);
819
820                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
821                     {
822                         ip0->hop_limit -= 1;
823                     }
824                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
825                     {
826                         ttl0 = ip0->hop_limit;
827                         exp0 = ip_dscp_to_mpls_exp(
828                             ip6_traffic_class_network_order(ip0));
829                     }
830
831                     /* save the payload proto information in mpls opaque */
832                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
833                 }
834                 else
835                 {
836                     /*
837                      * nothing to change in the ethernet header
838                      */
839                     ttl0 = MPLS_LABEL_DEFAULT_TTL;
840                     exp0 = MPLS_LABEL_DEFAULT_EXP;
841                 }
842
843                 /*
844                  * These are the non-MPLS payload imposition cases.
845                  * Based on the LSP mode either, for uniform, copy down the TTL
846                  * from the payload or, for pipe mode, slap on the value
847                  * requested from config
848                  */
849                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
850                 {
851                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
852                 }
853                 else
854                 {
855                     hdr0 = mpls_label_paint(b0, mld0);
856                 }
857             }
858             else
859             {
860                 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
861                 {
862                     ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
863
864                     ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
865                     exp0 = vnet_buffer(b0)->mpls.exp;
866                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
867                 }
868                 else
869                 {
870                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
871                     {
872                         hdr0 = vlib_buffer_get_current(b0);
873                         ttl0 = ((u8*)hdr0)[3];
874                         exp0 = ((u8*)hdr0)[2] & 0xe;
875                         hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
876                     }
877                     else
878                     {
879                         hdr0 = mpls_label_paint(b0, mld0);
880                     }
881                 }
882
883                 vnet_buffer(b0)->mpls.first = 0;
884             }
885
886             next0 = mld0->mld_dpo.dpoi_next_node;
887             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
888
889             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
890             {
891                 mpls_label_imposition_trace_t *tr =
892                     vlib_add_trace (vm, node, b0, sizeof (*tr));
893                 tr->hdr = *hdr0;
894                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
895                 {
896                     tr->ttl = ttl0;
897                     tr->exp = exp0;
898                 }
899                 else
900                 {
901                     tr->ttl = tr->exp = 0;
902                 }
903            }
904
905             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
906                                             n_left_to_next, bi0, next0);
907         }
908         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
909     }
910     return from_frame->n_vectors;
911 }
912
913 static u8 *
914 format_mpls_label_imposition_trace (u8 * s, va_list * args)
915 {
916     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
917     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
918     mpls_label_imposition_trace_t * t;
919     mpls_unicast_header_t hdr;
920     u32 indent;
921
922     t = va_arg (*args, mpls_label_imposition_trace_t *);
923     indent = format_get_indent (s);
924     hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
925
926     s = format (s, "%Umpls-header:%U",
927                 format_white_space, indent,
928                 format_mpls_header, hdr);
929     return (s);
930 }
931
932 VLIB_NODE_FN (mpls_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
933                                  vlib_node_runtime_t * node,
934                                  vlib_frame_t * frame)
935 {
936     return (mpls_label_imposition_inline(vm, node, frame,
937                                          DPO_PROTO_MPLS,
938                                          MPLS_LABEL_DPO_FLAG_NONE));
939 }
940
941 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = {
942     .name = "mpls-label-imposition-pipe",
943     .vector_size = sizeof (u32),
944
945     .format_trace = format_mpls_label_imposition_trace,
946     .n_next_nodes = 1,
947     .next_nodes = {
948         [0] = "mpls-drop",
949     }
950 };
951
952 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
953                                 vlib_node_runtime_t * node,
954                                 vlib_frame_t * frame)
955 {
956     return (mpls_label_imposition_inline(vm, node, frame,
957                                          DPO_PROTO_IP4,
958                                          MPLS_LABEL_DPO_FLAG_NONE));
959 }
960
961 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
962     .name = "ip4-mpls-label-imposition-pipe",
963     .vector_size = sizeof (u32),
964
965     .format_trace = format_mpls_label_imposition_trace,
966     .n_next_nodes = 1,
967     .next_nodes = {
968         [0] = "ip4-drop",
969     }
970 };
971
972 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
973                                 vlib_node_runtime_t * node,
974                                 vlib_frame_t * frame)
975 {
976     return (mpls_label_imposition_inline(vm, node, frame,
977                                          DPO_PROTO_IP6,
978                                          MPLS_LABEL_DPO_FLAG_NONE));
979 }
980
981 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
982     .name = "ip6-mpls-label-imposition-pipe",
983     .vector_size = sizeof (u32),
984
985     .format_trace = format_mpls_label_imposition_trace,
986     .n_next_nodes = 1,
987     .next_nodes = {
988         [0] = "ip6-drop",
989     }
990 };
991
992 VLIB_NODE_FN (ethernet_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
993                                      vlib_node_runtime_t * node,
994                                      vlib_frame_t * frame)
995 {
996     return (mpls_label_imposition_inline(vm, node, frame,
997                                          DPO_PROTO_ETHERNET,
998                                          MPLS_LABEL_DPO_FLAG_NONE));
999 }
1000
1001 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
1002     .name = "ethernet-mpls-label-imposition-pipe",
1003     .vector_size = sizeof (u32),
1004
1005     .format_trace = format_mpls_label_imposition_trace,
1006     .n_next_nodes = 1,
1007     .next_nodes = {
1008         [0] = "error-drop",
1009     }
1010 };
1011
1012 VLIB_NODE_FN (mpls_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1013                                     vlib_node_runtime_t * node,
1014                                     vlib_frame_t * frame)
1015 {
1016     return (mpls_label_imposition_inline(vm, node, frame,
1017                                          DPO_PROTO_MPLS,
1018                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1019 }
1020
1021 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
1022     .name = "mpls-label-imposition-uniform",
1023     .vector_size = sizeof (u32),
1024
1025     .format_trace = format_mpls_label_imposition_trace,
1026     .n_next_nodes = 1,
1027     .next_nodes = {
1028         [0] = "mpls-drop",
1029     }
1030 };
1031
1032 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1033                                    vlib_node_runtime_t * node,
1034                                    vlib_frame_t * frame)
1035 {
1036     return (mpls_label_imposition_inline(vm, node, frame,
1037                                          DPO_PROTO_IP4,
1038                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1039 }
1040
1041 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = {
1042     .name = "ip4-mpls-label-imposition-uniform",
1043     .vector_size = sizeof (u32),
1044
1045     .format_trace = format_mpls_label_imposition_trace,
1046     .n_next_nodes = 1,
1047     .next_nodes = {
1048         [0] = "ip4-drop",
1049     }
1050 };
1051
1052 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1053                                    vlib_node_runtime_t * node,
1054                                    vlib_frame_t * frame)
1055 {
1056     return (mpls_label_imposition_inline(vm, node, frame,
1057                                          DPO_PROTO_IP6,
1058                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1059 }
1060
1061 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1062     .name = "ip6-mpls-label-imposition-uniform",
1063     .vector_size = sizeof (u32),
1064
1065     .format_trace = format_mpls_label_imposition_trace,
1066     .n_next_nodes = 1,
1067     .next_nodes = {
1068         [0] = "ip6-drop",
1069     }
1070 };
1071
1072 VLIB_NODE_FN (ethernet_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1073                                         vlib_node_runtime_t * node,
1074                                         vlib_frame_t * frame)
1075 {
1076     return (mpls_label_imposition_inline(vm, node, frame,
1077                                          DPO_PROTO_ETHERNET,
1078                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1079 }
1080
1081 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1082     .name = "ethernet-mpls-label-imposition-uniform",
1083     .vector_size = sizeof (u32),
1084
1085     .format_trace = format_mpls_label_imposition_trace,
1086     .n_next_nodes = 1,
1087     .next_nodes = {
1088         [0] = "error-drop",
1089     }
1090 };
1091
1092
1093 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1094                                                vlib_node_runtime_t * node,
1095                                                vlib_frame_t * frame)
1096 {
1097     return (mpls_label_imposition_inline(vm, node, frame,
1098                                          DPO_PROTO_IP4,
1099                                          MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1100 }
1101
1102 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1103     .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1104     .vector_size = sizeof (u32),
1105
1106     .format_trace = format_mpls_label_imposition_trace,
1107     .n_next_nodes = 1,
1108     .next_nodes = {
1109         [0] = "ip4-drop",
1110     }
1111 };
1112
1113 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1114                                                vlib_node_runtime_t * node,
1115                                                vlib_frame_t * frame)
1116 {
1117     return (mpls_label_imposition_inline(vm, node, frame,
1118                                          DPO_PROTO_IP6,
1119                                          MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1120 }
1121
1122 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1123     .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1124     .vector_size = sizeof (u32),
1125
1126     .format_trace = format_mpls_label_imposition_trace,
1127     .n_next_nodes = 1,
1128     .next_nodes = {
1129         [0] = "ip6-drop",
1130     }
1131 };
1132
1133 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1134                                                   vlib_node_runtime_t * node,
1135                                                   vlib_frame_t * frame)
1136 {
1137     return (mpls_label_imposition_inline(vm, node, frame,
1138                                          DPO_PROTO_IP4,
1139                                          (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1140                                           MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1141 }
1142
1143 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1144     .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1145     .vector_size = sizeof (u32),
1146
1147     .format_trace = format_mpls_label_imposition_trace,
1148     .n_next_nodes = 1,
1149     .next_nodes = {
1150         [0] = "ip4-drop",
1151     }
1152 };
1153
1154 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1155                                                   vlib_node_runtime_t * node,
1156                                                   vlib_frame_t * frame)
1157 {
1158     return (mpls_label_imposition_inline(vm, node, frame,
1159                                          DPO_PROTO_IP6,
1160                                          (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1161                                           MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1162 }
1163
1164 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1165     .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1166     .vector_size = sizeof (u32),
1167
1168     .format_trace = format_mpls_label_imposition_trace,
1169     .n_next_nodes = 1,
1170     .next_nodes = {
1171         [0] = "ip6-drop",
1172     }
1173 };
1174
1175
1176 #ifndef CLIB_MARCH_VARIANT
1177 static void
1178 mpls_label_dpo_mem_show (void)
1179 {
1180     fib_show_memory_usage("MPLS label",
1181                           pool_elts(mpls_label_dpo_pool),
1182                           pool_len(mpls_label_dpo_pool),
1183                           sizeof(mpls_label_dpo_t));
1184 }
1185
1186 /**
1187  * Interpose a label DPO. used in the FIB unit tests
1188  */
1189 static void
1190 mpls_label_interpose (const dpo_id_t *original,
1191                       const dpo_id_t *parent,
1192                       dpo_id_t *clone)
1193 {
1194     mpls_label_dpo_t *mld, *mld_clone;
1195
1196     mld_clone = mpls_label_dpo_alloc();
1197     mld = mpls_label_dpo_get(original->dpoi_index);
1198
1199     mld_clone->mld_locks = 0;
1200     clib_memcpy_fast(&mld_clone->mld_hdr,
1201                 &mld->mld_hdr,
1202                 sizeof(mld_clone->mld_hdr));
1203     mld_clone->mld_payload_proto = mld->mld_payload_proto;
1204     mld_clone->mld_n_labels = mld->mld_n_labels;
1205     mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1206
1207     dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1208               mld_clone->mld_payload_proto,
1209               &mld_clone->mld_dpo,
1210               parent);
1211
1212     dpo_set(clone,
1213             mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1214             mld_clone->mld_payload_proto,
1215             mpls_label_dpo_get_index(mld_clone));
1216 }
1217
1218 static u16
1219 mpls_label_dpo_get_mtu (const dpo_id_t *dpo)
1220 {
1221     mpls_label_dpo_t *mld;
1222
1223     mld = mpls_label_dpo_get(dpo->dpoi_index);
1224
1225     /* return the parent's MTU minus the amount of header
1226      * this DPO imposes */
1227     return (dpo_get_mtu (&mld->mld_dpo) - sizeof(mpls_label_t) * mld->mld_n_labels);
1228 }
1229
1230 const static dpo_vft_t mld_vft = {
1231     .dv_lock = mpls_label_dpo_lock,
1232     .dv_unlock = mpls_label_dpo_unlock,
1233     .dv_format = format_mpls_label_dpo,
1234     .dv_mem_show = mpls_label_dpo_mem_show,
1235     .dv_mk_interpose = mpls_label_interpose,
1236     .dv_get_mtu = mpls_label_dpo_get_mtu,
1237 };
1238
1239 const static char* const mpls_label_imp_pipe_ip4_nodes[] =
1240 {
1241     "ip4-mpls-label-imposition-pipe",
1242     NULL,
1243 };
1244 const static char* const mpls_label_imp_pipe_ip6_nodes[] =
1245 {
1246     "ip6-mpls-label-imposition-pipe",
1247     NULL,
1248 };
1249 const static char* const mpls_label_imp_pipe_mpls_nodes[] =
1250 {
1251     "mpls-label-imposition-pipe",
1252     NULL,
1253 };
1254 const static char* const mpls_label_imp_pipe_ethernet_nodes[] =
1255 {
1256     "ethernet-mpls-label-imposition-pipe",
1257     NULL,
1258 };
1259
1260 const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] =
1261 {
1262     [DPO_PROTO_IP4]  = mpls_label_imp_pipe_ip4_nodes,
1263     [DPO_PROTO_IP6]  = mpls_label_imp_pipe_ip6_nodes,
1264     [DPO_PROTO_MPLS] = mpls_label_imp_pipe_mpls_nodes,
1265     [DPO_PROTO_ETHERNET] = mpls_label_imp_pipe_ethernet_nodes,
1266 };
1267
1268 const static char* const mpls_label_imp_uniform_ip4_nodes[] =
1269 {
1270     "ip4-mpls-label-imposition-uniform",
1271     NULL,
1272 };
1273 const static char* const mpls_label_imp_uniform_ip6_nodes[] =
1274 {
1275     "ip6-mpls-label-imposition-uniform",
1276     NULL,
1277 };
1278 const static char* const mpls_label_imp_uniform_mpls_nodes[] =
1279 {
1280     "mpls-label-imposition-uniform",
1281     NULL,
1282 };
1283 const static char* const mpls_label_imp_uniform_ethernet_nodes[] =
1284 {
1285     "ethernet-mpls-label-imposition-uniform",
1286     NULL,
1287 };
1288
1289 const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] =
1290 {
1291     [DPO_PROTO_IP4]  = mpls_label_imp_uniform_ip4_nodes,
1292     [DPO_PROTO_IP6]  = mpls_label_imp_uniform_ip6_nodes,
1293     [DPO_PROTO_MPLS] = mpls_label_imp_uniform_mpls_nodes,
1294     [DPO_PROTO_ETHERNET] = mpls_label_imp_uniform_ethernet_nodes,
1295 };
1296
1297 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] =
1298 {
1299     "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1300     NULL,
1301 };
1302 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] =
1303 {
1304     "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1305     NULL,
1306 };
1307
1308 const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1309 {
1310     [DPO_PROTO_IP4]  = mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes,
1311     [DPO_PROTO_IP6]  = mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes,
1312 };
1313
1314 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] =
1315 {
1316     "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1317     NULL,
1318 };
1319 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] =
1320 {
1321     "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1322     NULL,
1323 };
1324
1325 const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1326 {
1327     [DPO_PROTO_IP4]  = mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes,
1328     [DPO_PROTO_IP6]  = mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes,
1329 };
1330
1331 void
1332 mpls_label_dpo_module_init (void)
1333 {
1334     mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] =
1335         dpo_register_new_type(&mld_vft,
1336                               mpls_label_imp_pipe_nodes);
1337     mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1338         dpo_register_new_type(&mld_vft,
1339                               mpls_label_imp_pipe_no_ip_tll_decr_nodes);
1340     mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] =
1341         dpo_register_new_type(&mld_vft,
1342                               mpls_label_imp_uniform_nodes);
1343     mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1344                          MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1345         dpo_register_new_type(&mld_vft,
1346                               mpls_label_imp_uniform_no_ip_tll_decr_nodes);
1347 }
1348
1349 dpo_type_t
1350 mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1351 {
1352     return (mpls_label_dpo_types[flags]);
1353 }
1354 #endif /* CLIB_MARCH_VARIANT */
1355
1356 // clang-format on