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