virtio: Add RX queue full statisitics
[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     mld->mld_payload_proto = payload_proto;
88     dtype = mpls_label_dpo_types[flags];
89
90     if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
91     {
92         clib_warning("Label stack size exceeded");
93         dpo_stack(dtype,
94                   mld->mld_payload_proto,
95                   &mld->mld_dpo,
96                   drop_dpo_get(mld->mld_payload_proto));
97     }
98     else
99     {
100         mld->mld_n_labels = vec_len(label_stack);
101         mld->mld_n_hdr_bytes = mld->mld_n_labels * sizeof(mld->mld_hdr[0]);
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 *p4, *p5, *p6, *p7;
402
403               p4 = vlib_get_buffer (vm, from[4]);
404               p5 = vlib_get_buffer (vm, from[5]);
405               p6 = vlib_get_buffer (vm, from[6]);
406               p7 = vlib_get_buffer (vm, from[7]);
407
408               vlib_prefetch_buffer_header (p4, STORE);
409               vlib_prefetch_buffer_header (p5, STORE);
410               vlib_prefetch_buffer_header (p6, STORE);
411               vlib_prefetch_buffer_header (p7, STORE);
412
413               CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
414               CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
415               CLIB_PREFETCH (p6->data, sizeof (hdr0[0]), STORE);
416               CLIB_PREFETCH (p7->data, sizeof (hdr0[0]), STORE);
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                  * Save the l3 offset
444                  */
445                 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
446                 vnet_buffer (b1)->l3_hdr_offset = b1->current_data;
447                 vnet_buffer (b2)->l3_hdr_offset = b2->current_data;
448                 vnet_buffer (b3)->l3_hdr_offset = b3->current_data;
449
450                 if (DPO_PROTO_IP4 == dproto)
451                 {
452                     ip4_header_t * ip0 = vlib_buffer_get_current(b0);
453                     ip4_header_t * ip1 = vlib_buffer_get_current(b1);
454                     ip4_header_t * ip2 = vlib_buffer_get_current(b2);
455                     ip4_header_t * ip3 = vlib_buffer_get_current(b3);
456
457                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
458                     {
459                         /*
460                          * decrement the TTL on ingress to the LSP
461                          */
462                         u32 checksum0;
463                         u32 checksum1;
464                         u32 checksum2;
465                         u32 checksum3;
466
467                         checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
468                         checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
469                         checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
470                         checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
471
472                         checksum0 += checksum0 >= 0xffff;
473                         checksum1 += checksum1 >= 0xffff;
474                         checksum2 += checksum2 >= 0xffff;
475                         checksum3 += checksum3 >= 0xffff;
476
477                         ip0->checksum = checksum0;
478                         ip1->checksum = checksum1;
479                         ip2->checksum = checksum2;
480                         ip3->checksum = checksum3;
481
482                         ip0->ttl -= 1;
483                         ip1->ttl -= 1;
484                         ip2->ttl -= 1;
485                         ip3->ttl -= 1;
486                     }
487
488                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
489                     {
490                         ttl1 = ip1->ttl;
491                         ttl0 = ip0->ttl;
492                         ttl3 = ip3->ttl;
493                         ttl2 = ip2->ttl;
494                         /* by default copy the 3 most significant bits */
495                         exp0 = ip_dscp_to_mpls_exp(ip0->tos);
496                         exp1 = ip_dscp_to_mpls_exp(ip1->tos);
497                         exp2 = ip_dscp_to_mpls_exp(ip2->tos);
498                         exp3 = ip_dscp_to_mpls_exp(ip3->tos);
499                     }
500
501                     /* save the payload proto information in mpls opaque */
502                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
503                     vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP4;
504                     vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP4;
505                     vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP4;
506                 }
507                 else if (DPO_PROTO_IP6 == dproto)
508                 {
509                     /*
510                      * decrement the TTL on ingress to the LSP
511                      */
512                     ip6_header_t * ip0 = vlib_buffer_get_current(b0);
513                     ip6_header_t * ip1 = vlib_buffer_get_current(b1);
514                     ip6_header_t * ip2 = vlib_buffer_get_current(b2);
515                     ip6_header_t * ip3 = vlib_buffer_get_current(b3);
516
517                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
518                     {
519                         ip0->hop_limit -= 1;
520                         ip1->hop_limit -= 1;
521                         ip2->hop_limit -= 1;
522                         ip3->hop_limit -= 1;
523                     }
524                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
525                     {
526                         ttl0 = ip0->hop_limit;
527                         ttl1 = ip1->hop_limit;
528                         ttl2 = ip2->hop_limit;
529                         ttl3 = ip3->hop_limit;
530                         /* by default copy the 3 most significant bits */
531                         exp0 = ip_dscp_to_mpls_exp(
532                             ip6_traffic_class_network_order(ip0));
533                         exp1 = ip_dscp_to_mpls_exp(
534                             ip6_traffic_class_network_order(ip1));
535                         exp2 = ip_dscp_to_mpls_exp(
536                             ip6_traffic_class_network_order(ip2));
537                         exp3 = ip_dscp_to_mpls_exp(
538                             ip6_traffic_class_network_order(ip3));
539                     }
540
541                     /* save the payload proto information in mpls opaque */
542                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
543                     vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP6;
544                     vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP6;
545                     vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP6;
546                 }
547                 else
548                 {
549                     /*
550                      * nothing to change in the ethernet header
551                      */
552                     ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
553                     exp0 = exp1 = exp2 = exp3 = MPLS_LABEL_DEFAULT_EXP;
554                 }
555                 /*
556                  * These are the non-MPLS payload imposition cases.
557                  * Based on the LSP mode either, for uniform, copy down the TTL
558                  * and EXP from the payload or, for pipe mode, slap on the value
559                  * requested from config
560                  */
561                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
562                 {
563                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
564                     hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
565                     hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
566                     hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
567                 }
568                 else
569                 {
570                     hdr0 = mpls_label_paint(b0, mld0);
571                     hdr1 = mpls_label_paint(b1, mld1);
572                     hdr2 = mpls_label_paint(b2, mld2);
573                     hdr3 = mpls_label_paint(b3, mld3);
574                 }
575             }
576             else
577             {
578                 /*
579                  * else, the packet to be encapped is an MPLS packet
580                  * there are two cases to consider:
581                  *  1 - this is an MPLS label swap at an LSP midpoint.
582                  *      recognisable because mpls.first = 1. In this case the
583                  *      TTL must be set to the current value -1.
584                  *  2 - The MPLS packet is recursing (or being injected into)
585                  *      this LSP, in which case the pipe/uniform rules apply
586                  *
587                  */
588                 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
589                 {
590                     /*
591                      * The first label to be imposed on the packet. this is a
592                      * label swap.in which case we stashed the TTL and EXP bits
593                      * in the packet in the lookup node
594                      */
595                     ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
596
597                     ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
598                     exp0 = vnet_buffer(b0)->mpls.exp;
599                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
600                 }
601                 else
602                 {
603                     /*
604                      * not the first label. implying we are recusring down a
605                      * chain of output labels. Each layer is considered a new
606                      * LSP - hence the TTL/EXP are pipe/uniform handled
607                      */
608                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
609                     {
610                         hdr0 = vlib_buffer_get_current(b0);
611                         ttl0 = ((u8*)hdr0)[3];
612                         exp0 = ((u8*)hdr0)[2] & 0xe;
613                         hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
614                     }
615                     else
616                     {
617                         hdr0 = mpls_label_paint(b0, mld0);
618                     }
619                 }
620                 if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
621                 {
622                     ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
623
624                     ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
625                     exp1 = vnet_buffer(b1)->mpls.exp;
626                     hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
627                 }
628                 else
629                 {
630                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
631                     {
632                         hdr1 = vlib_buffer_get_current(b1);
633                         ttl1 = ((u8*)hdr1)[3];
634                         exp1 = ((u8*)hdr1)[2] & 0xe;
635                         hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
636                     }
637                     else
638                     {
639                         hdr1 = mpls_label_paint(b1, mld1);
640                     }
641                 }
642                 if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
643                 {
644                     ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
645
646                     ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
647                     exp2 = vnet_buffer(b2)->mpls.exp;
648                     hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
649                 }
650                 else
651                 {
652                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
653                     {
654                         hdr2 = vlib_buffer_get_current(b2);
655                         ttl2 = ((u8*)hdr2)[3];
656                         exp2 = ((u8*)hdr2)[2] & 0xe;
657                         hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
658                     }
659                     else
660                     {
661                         hdr2 = mpls_label_paint(b2, mld2);
662                     }
663                 }
664                 if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
665                 {
666                     ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
667
668                     ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
669                     exp3 = vnet_buffer(b3)->mpls.exp;
670                     hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
671                 }
672                 else
673                 {
674                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
675                     {
676                         hdr3 = vlib_buffer_get_current(b3);
677                         ttl3 = ((u8*)hdr3)[3];
678                         exp3 = ((u8*)hdr3)[2] & 0xe;
679                         hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
680                     }
681                     else
682                     {
683                         hdr3 = mpls_label_paint(b3, mld3);
684                     }
685                 }
686
687                 vnet_buffer(b0)->mpls.first = 0;
688                 vnet_buffer(b1)->mpls.first = 0;
689                 vnet_buffer(b2)->mpls.first = 0;
690                 vnet_buffer(b3)->mpls.first = 0;
691             }
692
693             next0 = mld0->mld_dpo.dpoi_next_node;
694             next1 = mld1->mld_dpo.dpoi_next_node;
695             next2 = mld2->mld_dpo.dpoi_next_node;
696             next3 = mld3->mld_dpo.dpoi_next_node;
697
698             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
699             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
700             vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
701             vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
702
703             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
704             {
705                 mpls_label_imposition_trace_t *tr =
706                     vlib_add_trace (vm, node, b0, sizeof (*tr));
707                 tr->hdr = *hdr0;
708                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
709                 {
710                     tr->ttl = ttl0;
711                     tr->exp = exp0;
712                 }
713                 else
714                 {
715                     tr->ttl = tr->exp = 0;
716                 }
717             }
718             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
719             {
720                 mpls_label_imposition_trace_t *tr =
721                     vlib_add_trace (vm, node, b1, sizeof (*tr));
722                 tr->hdr = *hdr1;
723                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
724                 {
725                     tr->ttl = ttl1;
726                     tr->exp = exp1;
727                 }
728                 else
729                 {
730                     tr->ttl = tr->exp = 0;
731                 }
732             }
733             if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
734             {
735                 mpls_label_imposition_trace_t *tr =
736                     vlib_add_trace (vm, node, b2, sizeof (*tr));
737                 tr->hdr = *hdr2;
738                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
739                 {
740                     tr->ttl = ttl2;
741                     tr->exp = exp2;
742                 }
743                 else
744                 {
745                     tr->ttl = tr->exp = 0;
746                 }
747             }
748             if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
749             {
750                 mpls_label_imposition_trace_t *tr =
751                     vlib_add_trace (vm, node, b3, sizeof (*tr));
752                 tr->hdr = *hdr3;
753                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
754                 {
755                     tr->ttl = ttl3;
756                     tr->exp = exp3;
757                 }
758                 else
759                 {
760                     tr->ttl = tr->exp = 0;
761                 }
762             }
763
764             vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next,
765                                             n_left_to_next,
766                                             bi0, bi1, bi2, bi3,
767                                             next0, next1, next2, next3);
768         }
769
770         while (n_left_from > 0 && n_left_to_next > 0)
771         {
772             mpls_unicast_header_t *hdr0;
773             mpls_label_dpo_t *mld0;
774             vlib_buffer_t * b0;
775             u32 bi0, mldi0;
776             u8 ttl0, exp0;
777             u32 next0;
778
779             bi0 = from[0];
780             to_next[0] = bi0;
781             from += 1;
782             to_next += 1;
783             n_left_from -= 1;
784             n_left_to_next -= 1;
785
786             b0 = vlib_get_buffer (vm, bi0);
787
788             /* dst lookup was done by ip4 lookup */
789             mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
790             mld0 = mpls_label_dpo_get(mldi0);
791
792             if (DPO_PROTO_MPLS != dproto)
793             {
794                 vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
795
796                 if (DPO_PROTO_IP4 == dproto)
797                 {
798                     /*
799                      * decrement the TTL on ingress to the LSP
800                      */
801                     ip4_header_t * ip0 = vlib_buffer_get_current(b0);
802                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
803                     {
804                         u32 checksum0;
805
806                         checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
807                         checksum0 += checksum0 >= 0xffff;
808
809                         ip0->checksum = checksum0;
810                         ip0->ttl -= 1;
811                     }
812                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
813                     {
814                         ttl0 = ip0->ttl;
815                         exp0 = ip_dscp_to_mpls_exp(ip0->tos);
816                     }
817
818                     /* save the payload proto information in mpls opaque */
819                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
820                 }
821                 else if (DPO_PROTO_IP6 == dproto)
822                 {
823                     /*
824                      * decrement the TTL on ingress to the LSP
825                      */
826                     ip6_header_t * ip0 = vlib_buffer_get_current(b0);
827
828                     if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
829                     {
830                         ip0->hop_limit -= 1;
831                     }
832                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
833                     {
834                         ttl0 = ip0->hop_limit;
835                         exp0 = ip_dscp_to_mpls_exp(
836                             ip6_traffic_class_network_order(ip0));
837                     }
838
839                     /* save the payload proto information in mpls opaque */
840                     vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
841                 }
842                 else
843                 {
844                     /*
845                      * nothing to change in the ethernet header
846                      */
847                     ttl0 = MPLS_LABEL_DEFAULT_TTL;
848                     exp0 = MPLS_LABEL_DEFAULT_EXP;
849                 }
850
851                 /*
852                  * These are the non-MPLS payload imposition cases.
853                  * Based on the LSP mode either, for uniform, copy down the TTL
854                  * from the payload or, for pipe mode, slap on the value
855                  * requested from config
856                  */
857                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
858                 {
859                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
860                 }
861                 else
862                 {
863                     hdr0 = mpls_label_paint(b0, mld0);
864                 }
865             }
866             else
867             {
868                 if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
869                 {
870                     ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
871
872                     ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
873                     exp0 = vnet_buffer(b0)->mpls.exp;
874                     hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
875                 }
876                 else
877                 {
878                     if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
879                     {
880                         hdr0 = vlib_buffer_get_current(b0);
881                         ttl0 = ((u8*)hdr0)[3];
882                         exp0 = ((u8*)hdr0)[2] & 0xe;
883                         hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
884                     }
885                     else
886                     {
887                         hdr0 = mpls_label_paint(b0, mld0);
888                     }
889                 }
890
891                 vnet_buffer(b0)->mpls.first = 0;
892             }
893
894             next0 = mld0->mld_dpo.dpoi_next_node;
895             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
896
897             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
898             {
899                 mpls_label_imposition_trace_t *tr =
900                     vlib_add_trace (vm, node, b0, sizeof (*tr));
901                 tr->hdr = *hdr0;
902                 if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
903                 {
904                     tr->ttl = ttl0;
905                     tr->exp = exp0;
906                 }
907                 else
908                 {
909                     tr->ttl = tr->exp = 0;
910                 }
911            }
912
913             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
914                                             n_left_to_next, bi0, next0);
915         }
916         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
917     }
918     return from_frame->n_vectors;
919 }
920
921 static u8 *
922 format_mpls_label_imposition_trace (u8 * s, va_list * args)
923 {
924     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
925     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
926     mpls_label_imposition_trace_t * t;
927     mpls_unicast_header_t hdr;
928     u32 indent;
929
930     t = va_arg (*args, mpls_label_imposition_trace_t *);
931     indent = format_get_indent (s);
932     hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
933
934     s = format (s, "%Umpls-header:%U",
935                 format_white_space, indent,
936                 format_mpls_header, hdr);
937     return (s);
938 }
939
940 VLIB_NODE_FN (mpls_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
941                                  vlib_node_runtime_t * node,
942                                  vlib_frame_t * frame)
943 {
944     return (mpls_label_imposition_inline(vm, node, frame,
945                                          DPO_PROTO_MPLS,
946                                          MPLS_LABEL_DPO_FLAG_NONE));
947 }
948
949 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_pipe_node) = {
950     .name = "mpls-label-imposition-pipe",
951     .vector_size = sizeof (u32),
952
953     .format_trace = format_mpls_label_imposition_trace,
954     .n_next_nodes = 1,
955     .next_nodes = {
956         [0] = "mpls-drop",
957     }
958 };
959
960 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
961                                 vlib_node_runtime_t * node,
962                                 vlib_frame_t * frame)
963 {
964     return (mpls_label_imposition_inline(vm, node, frame,
965                                          DPO_PROTO_IP4,
966                                          MPLS_LABEL_DPO_FLAG_NONE));
967 }
968
969 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_node) = {
970     .name = "ip4-mpls-label-imposition-pipe",
971     .vector_size = sizeof (u32),
972
973     .format_trace = format_mpls_label_imposition_trace,
974     .n_next_nodes = 1,
975     .next_nodes = {
976         [0] = "ip4-drop",
977     }
978 };
979
980 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
981                                 vlib_node_runtime_t * node,
982                                 vlib_frame_t * frame)
983 {
984     return (mpls_label_imposition_inline(vm, node, frame,
985                                          DPO_PROTO_IP6,
986                                          MPLS_LABEL_DPO_FLAG_NONE));
987 }
988
989 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_node) = {
990     .name = "ip6-mpls-label-imposition-pipe",
991     .vector_size = sizeof (u32),
992
993     .format_trace = format_mpls_label_imposition_trace,
994     .n_next_nodes = 1,
995     .next_nodes = {
996         [0] = "ip6-drop",
997     }
998 };
999
1000 VLIB_NODE_FN (ethernet_mpls_label_imposition_pipe_node) (vlib_main_t * vm,
1001                                      vlib_node_runtime_t * node,
1002                                      vlib_frame_t * frame)
1003 {
1004     return (mpls_label_imposition_inline(vm, node, frame,
1005                                          DPO_PROTO_ETHERNET,
1006                                          MPLS_LABEL_DPO_FLAG_NONE));
1007 }
1008
1009 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_pipe_node) = {
1010     .name = "ethernet-mpls-label-imposition-pipe",
1011     .vector_size = sizeof (u32),
1012
1013     .format_trace = format_mpls_label_imposition_trace,
1014     .n_next_nodes = 1,
1015     .next_nodes = {
1016         [0] = "error-drop",
1017     }
1018 };
1019
1020 VLIB_NODE_FN (mpls_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1021                                     vlib_node_runtime_t * node,
1022                                     vlib_frame_t * frame)
1023 {
1024     return (mpls_label_imposition_inline(vm, node, frame,
1025                                          DPO_PROTO_MPLS,
1026                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1027 }
1028
1029 VLIB_REGISTER_NODE (mpls_mpls_label_imposition_uniform_node) = {
1030     .name = "mpls-label-imposition-uniform",
1031     .vector_size = sizeof (u32),
1032
1033     .format_trace = format_mpls_label_imposition_trace,
1034     .n_next_nodes = 1,
1035     .next_nodes = {
1036         [0] = "mpls-drop",
1037     }
1038 };
1039
1040 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1041                                    vlib_node_runtime_t * node,
1042                                    vlib_frame_t * frame)
1043 {
1044     return (mpls_label_imposition_inline(vm, node, frame,
1045                                          DPO_PROTO_IP4,
1046                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1047 }
1048
1049 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_node) = {
1050     .name = "ip4-mpls-label-imposition-uniform",
1051     .vector_size = sizeof (u32),
1052
1053     .format_trace = format_mpls_label_imposition_trace,
1054     .n_next_nodes = 1,
1055     .next_nodes = {
1056         [0] = "ip4-drop",
1057     }
1058 };
1059
1060 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1061                                    vlib_node_runtime_t * node,
1062                                    vlib_frame_t * frame)
1063 {
1064     return (mpls_label_imposition_inline(vm, node, frame,
1065                                          DPO_PROTO_IP6,
1066                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1067 }
1068
1069 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_node) = {
1070     .name = "ip6-mpls-label-imposition-uniform",
1071     .vector_size = sizeof (u32),
1072
1073     .format_trace = format_mpls_label_imposition_trace,
1074     .n_next_nodes = 1,
1075     .next_nodes = {
1076         [0] = "ip6-drop",
1077     }
1078 };
1079
1080 VLIB_NODE_FN (ethernet_mpls_label_imposition_uniform_node) (vlib_main_t * vm,
1081                                         vlib_node_runtime_t * node,
1082                                         vlib_frame_t * frame)
1083 {
1084     return (mpls_label_imposition_inline(vm, node, frame,
1085                                          DPO_PROTO_ETHERNET,
1086                                          MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1087 }
1088
1089 VLIB_REGISTER_NODE (ethernet_mpls_label_imposition_uniform_node) = {
1090     .name = "ethernet-mpls-label-imposition-uniform",
1091     .vector_size = sizeof (u32),
1092
1093     .format_trace = format_mpls_label_imposition_trace,
1094     .n_next_nodes = 1,
1095     .next_nodes = {
1096         [0] = "error-drop",
1097     }
1098 };
1099
1100
1101 VLIB_NODE_FN (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1102                                                vlib_node_runtime_t * node,
1103                                                vlib_frame_t * frame)
1104 {
1105     return (mpls_label_imposition_inline(vm, node, frame,
1106                                          DPO_PROTO_IP4,
1107                                          MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1108 }
1109
1110 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1111     .name = "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1112     .vector_size = sizeof (u32),
1113
1114     .format_trace = format_mpls_label_imposition_trace,
1115     .n_next_nodes = 1,
1116     .next_nodes = {
1117         [0] = "ip4-drop",
1118     }
1119 };
1120
1121 VLIB_NODE_FN (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) (vlib_main_t * vm,
1122                                                vlib_node_runtime_t * node,
1123                                                vlib_frame_t * frame)
1124 {
1125     return (mpls_label_imposition_inline(vm, node, frame,
1126                                          DPO_PROTO_IP6,
1127                                          MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1128 }
1129
1130 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_pipe_no_ip_ttl_decr_node) = {
1131     .name = "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1132     .vector_size = sizeof (u32),
1133
1134     .format_trace = format_mpls_label_imposition_trace,
1135     .n_next_nodes = 1,
1136     .next_nodes = {
1137         [0] = "ip6-drop",
1138     }
1139 };
1140
1141 VLIB_NODE_FN (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1142                                                   vlib_node_runtime_t * node,
1143                                                   vlib_frame_t * frame)
1144 {
1145     return (mpls_label_imposition_inline(vm, node, frame,
1146                                          DPO_PROTO_IP4,
1147                                          (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1148                                           MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1149 }
1150
1151 VLIB_REGISTER_NODE (ip4_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1152     .name = "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1153     .vector_size = sizeof (u32),
1154
1155     .format_trace = format_mpls_label_imposition_trace,
1156     .n_next_nodes = 1,
1157     .next_nodes = {
1158         [0] = "ip4-drop",
1159     }
1160 };
1161
1162 VLIB_NODE_FN (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) (vlib_main_t * vm,
1163                                                   vlib_node_runtime_t * node,
1164                                                   vlib_frame_t * frame)
1165 {
1166     return (mpls_label_imposition_inline(vm, node, frame,
1167                                          DPO_PROTO_IP6,
1168                                          (MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1169                                           MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR)));
1170 }
1171
1172 VLIB_REGISTER_NODE (ip6_mpls_label_imposition_uniform_no_ip_ttl_decr_node) = {
1173     .name = "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1174     .vector_size = sizeof (u32),
1175
1176     .format_trace = format_mpls_label_imposition_trace,
1177     .n_next_nodes = 1,
1178     .next_nodes = {
1179         [0] = "ip6-drop",
1180     }
1181 };
1182
1183
1184 #ifndef CLIB_MARCH_VARIANT
1185 static void
1186 mpls_label_dpo_mem_show (void)
1187 {
1188     fib_show_memory_usage("MPLS label",
1189                           pool_elts(mpls_label_dpo_pool),
1190                           pool_len(mpls_label_dpo_pool),
1191                           sizeof(mpls_label_dpo_t));
1192 }
1193
1194 /**
1195  * Interpose a label DPO. used in the FIB unit tests
1196  */
1197 static void
1198 mpls_label_interpose (const dpo_id_t *original,
1199                       const dpo_id_t *parent,
1200                       dpo_id_t *clone)
1201 {
1202     mpls_label_dpo_t *mld, *mld_clone;
1203
1204     mld_clone = mpls_label_dpo_alloc();
1205     mld = mpls_label_dpo_get(original->dpoi_index);
1206
1207     mld_clone->mld_locks = 0;
1208     clib_memcpy_fast(&mld_clone->mld_hdr,
1209                 &mld->mld_hdr,
1210                 sizeof(mld_clone->mld_hdr));
1211     mld_clone->mld_payload_proto = mld->mld_payload_proto;
1212     mld_clone->mld_n_labels = mld->mld_n_labels;
1213     mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1214
1215     dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1216               mld_clone->mld_payload_proto,
1217               &mld_clone->mld_dpo,
1218               parent);
1219
1220     dpo_set(clone,
1221             mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1222             mld_clone->mld_payload_proto,
1223             mpls_label_dpo_get_index(mld_clone));
1224 }
1225
1226 static u16
1227 mpls_label_dpo_get_mtu (const dpo_id_t *dpo)
1228 {
1229     mpls_label_dpo_t *mld;
1230
1231     mld = mpls_label_dpo_get(dpo->dpoi_index);
1232
1233     /* return the parent's MTU minus the amount of header
1234      * this DPO imposes */
1235     return (dpo_get_mtu (&mld->mld_dpo) - sizeof(mpls_label_t) * mld->mld_n_labels);
1236 }
1237
1238 const static dpo_vft_t mld_vft = {
1239     .dv_lock = mpls_label_dpo_lock,
1240     .dv_unlock = mpls_label_dpo_unlock,
1241     .dv_format = format_mpls_label_dpo,
1242     .dv_mem_show = mpls_label_dpo_mem_show,
1243     .dv_mk_interpose = mpls_label_interpose,
1244     .dv_get_mtu = mpls_label_dpo_get_mtu,
1245 };
1246
1247 const static char* const mpls_label_imp_pipe_ip4_nodes[] =
1248 {
1249     "ip4-mpls-label-imposition-pipe",
1250     NULL,
1251 };
1252 const static char* const mpls_label_imp_pipe_ip6_nodes[] =
1253 {
1254     "ip6-mpls-label-imposition-pipe",
1255     NULL,
1256 };
1257 const static char* const mpls_label_imp_pipe_mpls_nodes[] =
1258 {
1259     "mpls-label-imposition-pipe",
1260     NULL,
1261 };
1262 const static char* const mpls_label_imp_pipe_ethernet_nodes[] =
1263 {
1264     "ethernet-mpls-label-imposition-pipe",
1265     NULL,
1266 };
1267
1268 const static char* const * const mpls_label_imp_pipe_nodes[DPO_PROTO_NUM] =
1269 {
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,
1274 };
1275
1276 const static char* const mpls_label_imp_uniform_ip4_nodes[] =
1277 {
1278     "ip4-mpls-label-imposition-uniform",
1279     NULL,
1280 };
1281 const static char* const mpls_label_imp_uniform_ip6_nodes[] =
1282 {
1283     "ip6-mpls-label-imposition-uniform",
1284     NULL,
1285 };
1286 const static char* const mpls_label_imp_uniform_mpls_nodes[] =
1287 {
1288     "mpls-label-imposition-uniform",
1289     NULL,
1290 };
1291 const static char* const mpls_label_imp_uniform_ethernet_nodes[] =
1292 {
1293     "ethernet-mpls-label-imposition-uniform",
1294     NULL,
1295 };
1296
1297 const static char* const * const mpls_label_imp_uniform_nodes[DPO_PROTO_NUM] =
1298 {
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,
1303 };
1304
1305 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip4_nodes[] =
1306 {
1307     "ip4-mpls-label-imposition-pipe-no-ip-ttl-decr",
1308     NULL,
1309 };
1310 const static char* const mpls_label_imp_pipe_no_ip_tll_decr_ip6_nodes[] =
1311 {
1312     "ip6-mpls-label-imposition-pipe-no-ip-ttl-decr",
1313     NULL,
1314 };
1315
1316 const static char* const * const mpls_label_imp_pipe_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1317 {
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,
1320 };
1321
1322 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip4_nodes[] =
1323 {
1324     "ip4-mpls-label-imposition-uniform-no-ip-ttl-decr",
1325     NULL,
1326 };
1327 const static char* const mpls_label_imp_uniform_no_ip_tll_decr_ip6_nodes[] =
1328 {
1329     "ip6-mpls-label-imposition-uniform-no-ip-ttl-decr",
1330     NULL,
1331 };
1332
1333 const static char* const * const mpls_label_imp_uniform_no_ip_tll_decr_nodes[DPO_PROTO_NUM] =
1334 {
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,
1337 };
1338
1339 void
1340 mpls_label_dpo_module_init (void)
1341 {
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);
1355 }
1356
1357 dpo_type_t
1358 mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1359 {
1360     return (mpls_label_dpo_types[flags]);
1361 }
1362 #endif /* CLIB_MARCH_VARIANT */
1363
1364 // clang-format on