Line data Source code
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 1783 : mpls_label_dpo_alloc (void)
42 : {
43 : mpls_label_dpo_t *mld;
44 : vlib_main_t *vm;
45 : u8 did_barrier_sync;
46 :
47 1783 : dpo_pool_barrier_sync (vm, mpls_label_dpo_pool, did_barrier_sync);
48 1783 : pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
49 1783 : dpo_pool_barrier_release (vm, did_barrier_sync);
50 :
51 1783 : clib_memset(mld, 0, sizeof(*mld));
52 :
53 1783 : dpo_reset(&mld->mld_dpo);
54 :
55 1783 : return (mld);
56 : }
57 :
58 : static index_t
59 1783 : mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
60 : {
61 1783 : return (mld - mpls_label_dpo_pool);
62 : }
63 :
64 : void
65 1769 : 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 1769 : if ((DPO_PROTO_IP4 != payload_proto) &&
77 : (DPO_PROTO_IP6 != payload_proto))
78 : {
79 : /*
80 : * remove unsupported configuration
81 : */
82 595 : flags &= ~MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
83 : }
84 :
85 1769 : mld = mpls_label_dpo_alloc();
86 1769 : mld->mld_flags = flags;
87 1769 : mld->mld_payload_proto = payload_proto;
88 1769 : dtype = mpls_label_dpo_types[flags];
89 :
90 1769 : if (MPLS_LABEL_DPO_MAX_N_LABELS < vec_len(label_stack))
91 : {
92 0 : clib_warning("Label stack size exceeded");
93 0 : dpo_stack(dtype,
94 0 : mld->mld_payload_proto,
95 : &mld->mld_dpo,
96 0 : drop_dpo_get(mld->mld_payload_proto));
97 : }
98 : else
99 : {
100 1769 : mld->mld_n_labels = vec_len(label_stack);
101 1769 : 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 2126 : for (ii = 0; ii < mld->mld_n_labels-1; ii++)
109 : {
110 357 : vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
111 357 : label_stack[ii].fml_value);
112 357 : vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
113 357 : label_stack[ii].fml_exp);
114 357 : vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl,
115 : MPLS_NON_EOS);
116 357 : if (0 != label_stack[ii].fml_ttl)
117 : {
118 338 : vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
119 338 : label_stack[ii].fml_ttl);
120 : }
121 : else
122 : {
123 19 : vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
124 : MPLS_LABEL_DEFAULT_TTL);
125 : }
126 357 : mld->mld_hdr[ii].label_exp_s_ttl =
127 357 : clib_host_to_net_u32(mld->mld_hdr[ii].label_exp_s_ttl);
128 : }
129 :
130 : /*
131 : * the inner most label
132 : */
133 1769 : ii = mld->mld_n_labels-1;
134 :
135 1769 : vnet_mpls_uc_set_label(&mld->mld_hdr[ii].label_exp_s_ttl,
136 1769 : label_stack[ii].fml_value);
137 1769 : vnet_mpls_uc_set_exp(&mld->mld_hdr[ii].label_exp_s_ttl,
138 1769 : label_stack[ii].fml_exp);
139 1769 : vnet_mpls_uc_set_s(&mld->mld_hdr[ii].label_exp_s_ttl, eos);
140 1769 : if (0 != label_stack[ii].fml_ttl)
141 : {
142 1677 : vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
143 1677 : label_stack[ii].fml_ttl);
144 : }
145 : else
146 : {
147 92 : vnet_mpls_uc_set_ttl(&mld->mld_hdr[ii].label_exp_s_ttl,
148 : MPLS_LABEL_DEFAULT_TTL);
149 : }
150 1769 : mld->mld_hdr[ii].label_exp_s_ttl =
151 1769 : 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 1769 : if (FIB_MPLS_LSP_MODE_UNIFORM == label_stack[ii].fml_mode)
157 : {
158 341 : mld->mld_flags |= MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
159 : }
160 : else
161 : {
162 1428 : mld->mld_flags &= ~MPLS_LABEL_DPO_FLAG_UNIFORM_MODE;
163 : }
164 1769 : dtype = mpls_label_dpo_types[mld->mld_flags];
165 :
166 : /*
167 : * stack this label object on its parent.
168 : */
169 1769 : dpo_stack(dtype,
170 1769 : mld->mld_payload_proto,
171 : &mld->mld_dpo,
172 : parent);
173 : }
174 :
175 1769 : dpo_set(dpo,
176 : dtype,
177 1769 : mld->mld_payload_proto,
178 : mpls_label_dpo_get_index(mld));
179 1769 : }
180 :
181 : u8*
182 1207 : format_mpls_label_dpo_flags (u8 *s, va_list *args)
183 : {
184 1207 : mpls_label_dpo_flags_t flags = va_arg (*args, int);
185 : mpls_label_dpo_attr_t attr;
186 :
187 3621 : FOR_EACH_MPLS_LABEL_DPO_ATTR(attr)
188 : {
189 2414 : if ((1 << attr) & flags)
190 : {
191 352 : s = format(s, "%s,", mpls_label_dpo_attr_names[attr]);
192 : }
193 : }
194 :
195 1207 : return (s);
196 : }
197 :
198 : u8*
199 2235 : format_mpls_label_dpo (u8 *s, va_list *args)
200 : {
201 2235 : index_t index = va_arg (*args, index_t);
202 2235 : u32 indent = va_arg (*args, u32);
203 : mpls_unicast_header_t hdr;
204 : mpls_label_dpo_t *mld;
205 : u32 ii;
206 :
207 2235 : 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 1028 : return (format(s, "mpls-label[???,%d]:", index));
213 : }
214 :
215 1207 : mld = mpls_label_dpo_get(index);
216 1207 : s = format(s, "mpls-label[%U@%d]:",
217 : format_mpls_label_dpo_flags,
218 1207 : (int) mld->mld_flags, index);
219 :
220 3415 : for (ii = 0; ii < mld->mld_n_labels; ii++)
221 : {
222 2208 : hdr.label_exp_s_ttl =
223 2208 : clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
224 2208 : s = format(s, "%U", format_mpls_header, hdr);
225 : }
226 :
227 1207 : s = format(s, "\n%U", format_white_space, indent);
228 1207 : s = format(s, "%U", format_dpo_id, &mld->mld_dpo, indent+2);
229 :
230 1207 : return (s);
231 : }
232 :
233 : static void
234 5451 : mpls_label_dpo_lock (dpo_id_t *dpo)
235 : {
236 : mpls_label_dpo_t *mld;
237 :
238 5451 : mld = mpls_label_dpo_get(dpo->dpoi_index);
239 :
240 5451 : mld->mld_locks++;
241 5451 : }
242 :
243 : static void
244 5451 : mpls_label_dpo_unlock (dpo_id_t *dpo)
245 : {
246 : mpls_label_dpo_t *mld;
247 :
248 5451 : mld = mpls_label_dpo_get(dpo->dpoi_index);
249 :
250 5451 : mld->mld_locks--;
251 :
252 5451 : if (0 == mld->mld_locks)
253 : {
254 1783 : dpo_reset(&mld->mld_dpo);
255 1783 : pool_put(mpls_label_dpo_pool, mld);
256 : }
257 5451 : }
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 19908 : mpls_label_paint (vlib_buffer_t * b0,
284 : mpls_label_dpo_t *mld0)
285 : {
286 : mpls_unicast_header_t *hdr0;
287 :
288 19908 : vlib_buffer_advance(b0, -(mld0->mld_n_hdr_bytes));
289 :
290 19908 : hdr0 = vlib_buffer_get_current(b0);
291 :
292 19908 : if (1 == mld0->mld_n_labels)
293 : {
294 : /* optimise for the common case of one label */
295 13930 : *hdr0 = mld0->mld_hdr[0];
296 : }
297 : else
298 : {
299 5978 : clib_memcpy_fast(hdr0, mld0->mld_hdr, mld0->mld_n_hdr_bytes);
300 5978 : hdr0 = hdr0 + (mld0->mld_n_labels - 1);
301 : }
302 :
303 19908 : return (hdr0);
304 : }
305 :
306 : /**
307 : * Paint on an MPLS label and fixup the TTL
308 : */
309 : always_inline mpls_unicast_header_t *
310 5024 : 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 5024 : hdr0 = mpls_label_paint(b0, mld0);
317 :
318 : /* fixup the TTL for the inner most label */
319 5024 : ((char*)hdr0)[3] = ttl0;
320 :
321 5024 : 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 4510 : 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 4510 : hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
336 :
337 : /* fixup the EXP for the inner most label */
338 4510 : ((char*)hdr0)[2] |= (exp0 << 1);
339 :
340 4510 : 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 514 : 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 514 : hdr0 = mpls_label_paint_w_ttl(b0, mld0, ttl0);
357 :
358 : /* fixup the EXP for the inner most label */
359 514 : ((char*)hdr0)[2] |= exp0;
360 :
361 514 : return (hdr0);
362 : }
363 :
364 : always_inline uword
365 171 : 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 171 : from = vlib_frame_vector_args (from_frame);
374 171 : n_left_from = from_frame->n_vectors;
375 :
376 171 : next_index = node->cached_next_index;
377 :
378 342 : while (n_left_from > 0)
379 : {
380 : u32 n_left_to_next;
381 :
382 171 : vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
383 :
384 5017 : 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 4846 : bi0 = to_next[0] = from[0];
395 4846 : bi1 = to_next[1] = from[1];
396 4846 : bi2 = to_next[2] = from[2];
397 4846 : bi3 = to_next[3] = from[3];
398 :
399 : /* Prefetch next iteration. */
400 : {
401 : vlib_buffer_t *p4, *p5, *p6, *p7;
402 :
403 4846 : p4 = vlib_get_buffer (vm, from[4]);
404 4846 : p5 = vlib_get_buffer (vm, from[5]);
405 4846 : p6 = vlib_get_buffer (vm, from[6]);
406 4846 : p7 = vlib_get_buffer (vm, from[7]);
407 :
408 4846 : vlib_prefetch_buffer_header (p4, STORE);
409 4846 : vlib_prefetch_buffer_header (p5, STORE);
410 4846 : vlib_prefetch_buffer_header (p6, STORE);
411 4846 : vlib_prefetch_buffer_header (p7, STORE);
412 :
413 4846 : CLIB_PREFETCH (p4->data, sizeof (hdr0[0]), STORE);
414 4846 : CLIB_PREFETCH (p5->data, sizeof (hdr0[0]), STORE);
415 4846 : CLIB_PREFETCH (p6->data, sizeof (hdr0[0]), STORE);
416 4846 : CLIB_PREFETCH (p7->data, sizeof (hdr0[0]), STORE);
417 : }
418 :
419 4846 : from += 4;
420 4846 : to_next += 4;
421 4846 : n_left_from -= 4;
422 4846 : n_left_to_next -= 4;
423 :
424 4846 : b0 = vlib_get_buffer (vm, bi0);
425 4846 : b1 = vlib_get_buffer (vm, bi1);
426 4846 : b2 = vlib_get_buffer (vm, bi2);
427 4846 : b3 = vlib_get_buffer (vm, bi3);
428 :
429 : /* dst lookup was done by ip4 lookup */
430 4846 : mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
431 4846 : mldi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
432 4846 : mldi2 = vnet_buffer(b2)->ip.adj_index[VLIB_TX];
433 4846 : mldi3 = vnet_buffer(b3)->ip.adj_index[VLIB_TX];
434 4846 : mld0 = mpls_label_dpo_get(mldi0);
435 4846 : mld1 = mpls_label_dpo_get(mldi1);
436 4846 : mld2 = mpls_label_dpo_get(mldi2);
437 4846 : mld3 = mpls_label_dpo_get(mldi3);
438 :
439 4846 : if (DPO_PROTO_MPLS != dproto)
440 : {
441 : /*
442 : * These are the non-MPLS payload imposition cases.
443 : * Save the l3 offset
444 : */
445 2317 : vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
446 2317 : vnet_buffer (b1)->l3_hdr_offset = b1->current_data;
447 2317 : vnet_buffer (b2)->l3_hdr_offset = b2->current_data;
448 2317 : vnet_buffer (b3)->l3_hdr_offset = b3->current_data;
449 :
450 2317 : if (DPO_PROTO_IP4 == dproto)
451 : {
452 2039 : ip4_header_t * ip0 = vlib_buffer_get_current(b0);
453 2039 : ip4_header_t * ip1 = vlib_buffer_get_current(b1);
454 2039 : ip4_header_t * ip2 = vlib_buffer_get_current(b2);
455 2039 : ip4_header_t * ip3 = vlib_buffer_get_current(b3);
456 :
457 2039 : 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 1472 : checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
468 1472 : checksum1 = ip1->checksum + clib_host_to_net_u16 (0x0100);
469 1472 : checksum2 = ip2->checksum + clib_host_to_net_u16 (0x0100);
470 1472 : checksum3 = ip3->checksum + clib_host_to_net_u16 (0x0100);
471 :
472 1472 : checksum0 += checksum0 >= 0xffff;
473 1472 : checksum1 += checksum1 >= 0xffff;
474 1472 : checksum2 += checksum2 >= 0xffff;
475 1472 : checksum3 += checksum3 >= 0xffff;
476 :
477 1472 : ip0->checksum = checksum0;
478 1472 : ip1->checksum = checksum1;
479 1472 : ip2->checksum = checksum2;
480 1472 : ip3->checksum = checksum3;
481 :
482 1472 : ip0->ttl -= 1;
483 1472 : ip1->ttl -= 1;
484 1472 : ip2->ttl -= 1;
485 1472 : ip3->ttl -= 1;
486 : }
487 :
488 2039 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
489 : {
490 126 : ttl1 = ip1->ttl;
491 126 : ttl0 = ip0->ttl;
492 126 : ttl3 = ip3->ttl;
493 126 : ttl2 = ip2->ttl;
494 : /* by default copy the 3 most significant bits */
495 126 : exp0 = ip_dscp_to_mpls_exp(ip0->tos);
496 126 : exp1 = ip_dscp_to_mpls_exp(ip1->tos);
497 126 : exp2 = ip_dscp_to_mpls_exp(ip2->tos);
498 126 : exp3 = ip_dscp_to_mpls_exp(ip3->tos);
499 : }
500 :
501 : /* save the payload proto information in mpls opaque */
502 2039 : vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
503 2039 : vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP4;
504 2039 : vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP4;
505 2039 : vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP4;
506 : }
507 278 : else if (DPO_PROTO_IP6 == dproto)
508 : {
509 : /*
510 : * decrement the TTL on ingress to the LSP
511 : */
512 233 : ip6_header_t * ip0 = vlib_buffer_get_current(b0);
513 233 : ip6_header_t * ip1 = vlib_buffer_get_current(b1);
514 233 : ip6_header_t * ip2 = vlib_buffer_get_current(b2);
515 233 : ip6_header_t * ip3 = vlib_buffer_get_current(b3);
516 :
517 233 : if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
518 : {
519 233 : ip0->hop_limit -= 1;
520 233 : ip1->hop_limit -= 1;
521 233 : ip2->hop_limit -= 1;
522 233 : ip3->hop_limit -= 1;
523 : }
524 233 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
525 : {
526 63 : ttl0 = ip0->hop_limit;
527 63 : ttl1 = ip1->hop_limit;
528 63 : ttl2 = ip2->hop_limit;
529 63 : ttl3 = ip3->hop_limit;
530 : /* by default copy the 3 most significant bits */
531 63 : exp0 = ip_dscp_to_mpls_exp(
532 63 : ip6_traffic_class_network_order(ip0));
533 63 : exp1 = ip_dscp_to_mpls_exp(
534 63 : ip6_traffic_class_network_order(ip1));
535 63 : exp2 = ip_dscp_to_mpls_exp(
536 63 : ip6_traffic_class_network_order(ip2));
537 63 : exp3 = ip_dscp_to_mpls_exp(
538 63 : ip6_traffic_class_network_order(ip3));
539 : }
540 :
541 : /* save the payload proto information in mpls opaque */
542 233 : vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
543 233 : vnet_buffer(b1)->mpls.pyld_proto = DPO_PROTO_IP6;
544 233 : vnet_buffer(b2)->mpls.pyld_proto = DPO_PROTO_IP6;
545 233 : vnet_buffer(b3)->mpls.pyld_proto = DPO_PROTO_IP6;
546 : }
547 : else
548 : {
549 : /*
550 : * nothing to change in the ethernet header
551 : */
552 45 : ttl0 = ttl1 = ttl2 = ttl3 = MPLS_LABEL_DEFAULT_TTL;
553 45 : 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 2317 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
562 : {
563 204 : hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
564 204 : hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
565 204 : hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
566 204 : hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
567 : }
568 : else
569 : {
570 2113 : hdr0 = mpls_label_paint(b0, mld0);
571 2113 : hdr1 = mpls_label_paint(b1, mld1);
572 2113 : hdr2 = mpls_label_paint(b2, mld2);
573 2113 : 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 2529 : 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 894 : ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
596 :
597 894 : ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
598 894 : exp0 = vnet_buffer(b0)->mpls.exp;
599 894 : 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 1635 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
609 : {
610 126 : hdr0 = vlib_buffer_get_current(b0);
611 126 : ttl0 = ((u8*)hdr0)[3];
612 126 : exp0 = ((u8*)hdr0)[2] & 0xe;
613 126 : hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
614 : }
615 : else
616 : {
617 1509 : hdr0 = mpls_label_paint(b0, mld0);
618 : }
619 : }
620 2529 : if (PREDICT_TRUE(vnet_buffer(b1)->mpls.first))
621 : {
622 894 : ASSERT(0 != vnet_buffer (b1)->mpls.ttl);
623 :
624 894 : ttl1 = vnet_buffer(b1)->mpls.ttl - 1;
625 894 : exp1 = vnet_buffer(b1)->mpls.exp;
626 894 : hdr1 = mpls_label_paint_w_ttl_exp(b1, mld1, ttl1, exp1);
627 : }
628 : else
629 : {
630 1635 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
631 : {
632 126 : hdr1 = vlib_buffer_get_current(b1);
633 126 : ttl1 = ((u8*)hdr1)[3];
634 126 : exp1 = ((u8*)hdr1)[2] & 0xe;
635 126 : hdr1 = mpls_label_paint_w_ttl_mpls_exp(b1, mld1, ttl1, exp1);
636 : }
637 : else
638 : {
639 1509 : hdr1 = mpls_label_paint(b1, mld1);
640 : }
641 : }
642 2529 : if (PREDICT_TRUE(vnet_buffer(b2)->mpls.first))
643 : {
644 894 : ASSERT(0 != vnet_buffer (b2)->mpls.ttl);
645 :
646 894 : ttl2 = vnet_buffer(b2)->mpls.ttl - 1;
647 894 : exp2 = vnet_buffer(b2)->mpls.exp;
648 894 : hdr2 = mpls_label_paint_w_ttl_exp(b2, mld2, ttl2, exp2);
649 : }
650 : else
651 : {
652 1635 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
653 : {
654 126 : hdr2 = vlib_buffer_get_current(b2);
655 126 : ttl2 = ((u8*)hdr2)[3];
656 126 : exp2 = ((u8*)hdr2)[2] & 0xe;
657 126 : hdr2 = mpls_label_paint_w_ttl_mpls_exp(b2, mld2, ttl2, exp2);
658 : }
659 : else
660 : {
661 1509 : hdr2 = mpls_label_paint(b2, mld2);
662 : }
663 : }
664 2529 : if (PREDICT_TRUE(vnet_buffer(b3)->mpls.first))
665 : {
666 894 : ASSERT(0 != vnet_buffer (b3)->mpls.ttl);
667 :
668 894 : ttl3 = vnet_buffer(b3)->mpls.ttl - 1;
669 894 : exp3 = vnet_buffer(b3)->mpls.exp;
670 894 : hdr3 = mpls_label_paint_w_ttl_exp(b3, mld3, ttl3, exp3);
671 : }
672 : else
673 : {
674 1635 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
675 : {
676 126 : hdr3 = vlib_buffer_get_current(b3);
677 126 : ttl3 = ((u8*)hdr3)[3];
678 126 : exp3 = ((u8*)hdr3)[2] & 0xe;
679 126 : hdr3 = mpls_label_paint_w_ttl_mpls_exp(b3, mld3, ttl3, exp3);
680 : }
681 : else
682 : {
683 1509 : hdr3 = mpls_label_paint(b3, mld3);
684 : }
685 : }
686 :
687 2529 : vnet_buffer(b0)->mpls.first = 0;
688 2529 : vnet_buffer(b1)->mpls.first = 0;
689 2529 : vnet_buffer(b2)->mpls.first = 0;
690 2529 : vnet_buffer(b3)->mpls.first = 0;
691 : }
692 :
693 4846 : next0 = mld0->mld_dpo.dpoi_next_node;
694 4846 : next1 = mld1->mld_dpo.dpoi_next_node;
695 4846 : next2 = mld2->mld_dpo.dpoi_next_node;
696 4846 : next3 = mld3->mld_dpo.dpoi_next_node;
697 :
698 4846 : vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
699 4846 : vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mld1->mld_dpo.dpoi_index;
700 4846 : vnet_buffer(b2)->ip.adj_index[VLIB_TX] = mld2->mld_dpo.dpoi_index;
701 4846 : vnet_buffer(b3)->ip.adj_index[VLIB_TX] = mld3->mld_dpo.dpoi_index;
702 :
703 4846 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
704 : {
705 : mpls_label_imposition_trace_t *tr =
706 4846 : vlib_add_trace (vm, node, b0, sizeof (*tr));
707 4846 : tr->hdr = *hdr0;
708 4846 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
709 : {
710 393 : tr->ttl = ttl0;
711 393 : tr->exp = exp0;
712 : }
713 : else
714 : {
715 4453 : tr->ttl = tr->exp = 0;
716 : }
717 : }
718 4846 : if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
719 : {
720 : mpls_label_imposition_trace_t *tr =
721 4846 : vlib_add_trace (vm, node, b1, sizeof (*tr));
722 4846 : tr->hdr = *hdr1;
723 4846 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
724 : {
725 393 : tr->ttl = ttl1;
726 393 : tr->exp = exp1;
727 : }
728 : else
729 : {
730 4453 : tr->ttl = tr->exp = 0;
731 : }
732 : }
733 4846 : if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
734 : {
735 : mpls_label_imposition_trace_t *tr =
736 4846 : vlib_add_trace (vm, node, b2, sizeof (*tr));
737 4846 : tr->hdr = *hdr2;
738 4846 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
739 : {
740 393 : tr->ttl = ttl2;
741 393 : tr->exp = exp2;
742 : }
743 : else
744 : {
745 4453 : tr->ttl = tr->exp = 0;
746 : }
747 : }
748 4846 : if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
749 : {
750 : mpls_label_imposition_trace_t *tr =
751 4846 : vlib_add_trace (vm, node, b3, sizeof (*tr));
752 4846 : tr->hdr = *hdr3;
753 4846 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
754 : {
755 393 : tr->ttl = ttl3;
756 393 : tr->exp = exp3;
757 : }
758 : else
759 : {
760 4453 : tr->ttl = tr->exp = 0;
761 : }
762 : }
763 :
764 4846 : 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 695 : 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 524 : bi0 = from[0];
780 524 : to_next[0] = bi0;
781 524 : from += 1;
782 524 : to_next += 1;
783 524 : n_left_from -= 1;
784 524 : n_left_to_next -= 1;
785 :
786 524 : b0 = vlib_get_buffer (vm, bi0);
787 :
788 : /* dst lookup was done by ip4 lookup */
789 524 : mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
790 524 : mld0 = mpls_label_dpo_get(mldi0);
791 :
792 524 : if (DPO_PROTO_MPLS != dproto)
793 : {
794 274 : vnet_buffer (b0)->l3_hdr_offset = b0->current_data;
795 :
796 274 : if (DPO_PROTO_IP4 == dproto)
797 : {
798 : /*
799 : * decrement the TTL on ingress to the LSP
800 : */
801 216 : ip4_header_t * ip0 = vlib_buffer_get_current(b0);
802 216 : if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
803 : {
804 : u32 checksum0;
805 :
806 171 : checksum0 = ip0->checksum + clib_host_to_net_u16 (0x0100);
807 171 : checksum0 += checksum0 >= 0xffff;
808 :
809 171 : ip0->checksum = checksum0;
810 171 : ip0->ttl -= 1;
811 : }
812 216 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
813 : {
814 10 : ttl0 = ip0->ttl;
815 10 : exp0 = ip_dscp_to_mpls_exp(ip0->tos);
816 : }
817 :
818 : /* save the payload proto information in mpls opaque */
819 216 : vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP4;
820 : }
821 58 : else if (DPO_PROTO_IP6 == dproto)
822 : {
823 : /*
824 : * decrement the TTL on ingress to the LSP
825 : */
826 32 : ip6_header_t * ip0 = vlib_buffer_get_current(b0);
827 :
828 32 : if (!(MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR & flags))
829 : {
830 32 : ip0->hop_limit -= 1;
831 : }
832 32 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
833 : {
834 5 : ttl0 = ip0->hop_limit;
835 5 : exp0 = ip_dscp_to_mpls_exp(
836 5 : ip6_traffic_class_network_order(ip0));
837 : }
838 :
839 : /* save the payload proto information in mpls opaque */
840 32 : vnet_buffer(b0)->mpls.pyld_proto = DPO_PROTO_IP6;
841 : }
842 : else
843 : {
844 : /*
845 : * nothing to change in the ethernet header
846 : */
847 26 : ttl0 = MPLS_LABEL_DEFAULT_TTL;
848 26 : 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 274 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
858 : {
859 23 : hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
860 : }
861 : else
862 : {
863 251 : hdr0 = mpls_label_paint(b0, mld0);
864 : }
865 : }
866 : else
867 : {
868 250 : if (PREDICT_TRUE(vnet_buffer(b0)->mpls.first))
869 : {
870 95 : ASSERT(0 != vnet_buffer (b0)->mpls.ttl);
871 :
872 95 : ttl0 = vnet_buffer(b0)->mpls.ttl - 1;
873 95 : exp0 = vnet_buffer(b0)->mpls.exp;
874 95 : hdr0 = mpls_label_paint_w_ttl_exp(b0, mld0, ttl0, exp0);
875 : }
876 : else
877 : {
878 155 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
879 : {
880 10 : hdr0 = vlib_buffer_get_current(b0);
881 10 : ttl0 = ((u8*)hdr0)[3];
882 10 : exp0 = ((u8*)hdr0)[2] & 0xe;
883 10 : hdr0 = mpls_label_paint_w_ttl_mpls_exp(b0, mld0, ttl0, exp0);
884 : }
885 : else
886 : {
887 145 : hdr0 = mpls_label_paint(b0, mld0);
888 : }
889 : }
890 :
891 250 : vnet_buffer(b0)->mpls.first = 0;
892 : }
893 :
894 524 : next0 = mld0->mld_dpo.dpoi_next_node;
895 524 : vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
896 :
897 524 : if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
898 : {
899 : mpls_label_imposition_trace_t *tr =
900 524 : vlib_add_trace (vm, node, b0, sizeof (*tr));
901 524 : tr->hdr = *hdr0;
902 524 : if (flags & MPLS_LABEL_DPO_FLAG_UNIFORM_MODE)
903 : {
904 38 : tr->ttl = ttl0;
905 38 : tr->exp = exp0;
906 : }
907 : else
908 : {
909 486 : tr->ttl = tr->exp = 0;
910 : }
911 : }
912 :
913 524 : vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
914 : n_left_to_next, bi0, next0);
915 : }
916 171 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
917 : }
918 171 : return from_frame->n_vectors;
919 : }
920 :
921 : static u8 *
922 10574 : format_mpls_label_imposition_trace (u8 * s, va_list * args)
923 : {
924 10574 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
925 10574 : 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 10574 : t = va_arg (*args, mpls_label_imposition_trace_t *);
931 10574 : indent = format_get_indent (s);
932 10574 : hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
933 :
934 10574 : s = format (s, "%Umpls-header:%U",
935 : format_white_space, indent,
936 : format_mpls_header, hdr);
937 10574 : return (s);
938 : }
939 :
940 2379 : 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 79 : return (mpls_label_imposition_inline(vm, node, frame,
945 : DPO_PROTO_MPLS,
946 : MPLS_LABEL_DPO_FLAG_NONE));
947 : }
948 :
949 183788 : 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 2352 : 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 52 : return (mpls_label_imposition_inline(vm, node, frame,
965 : DPO_PROTO_IP4,
966 : MPLS_LABEL_DPO_FLAG_NONE));
967 : }
968 :
969 183788 : 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 2309 : 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 9 : return (mpls_label_imposition_inline(vm, node, frame,
985 : DPO_PROTO_IP6,
986 : MPLS_LABEL_DPO_FLAG_NONE));
987 : }
988 :
989 183788 : 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 2304 : 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 4 : return (mpls_label_imposition_inline(vm, node, frame,
1005 : DPO_PROTO_ETHERNET,
1006 : MPLS_LABEL_DPO_FLAG_NONE));
1007 : }
1008 :
1009 183788 : 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 2306 : 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 6 : return (mpls_label_imposition_inline(vm, node, frame,
1025 : DPO_PROTO_MPLS,
1026 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1027 : }
1028 :
1029 183788 : 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 2302 : 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 2 : return (mpls_label_imposition_inline(vm, node, frame,
1045 : DPO_PROTO_IP4,
1046 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1047 : }
1048 :
1049 183788 : 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 2302 : 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 2 : return (mpls_label_imposition_inline(vm, node, frame,
1065 : DPO_PROTO_IP6,
1066 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1067 : }
1068 :
1069 183788 : 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 2302 : 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 2 : return (mpls_label_imposition_inline(vm, node, frame,
1085 : DPO_PROTO_ETHERNET,
1086 : MPLS_LABEL_DPO_FLAG_UNIFORM_MODE));
1087 : }
1088 :
1089 183788 : 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 2313 : 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 13 : return (mpls_label_imposition_inline(vm, node, frame,
1106 : DPO_PROTO_IP4,
1107 : MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1108 : }
1109 :
1110 183788 : 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 2300 : 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 0 : return (mpls_label_imposition_inline(vm, node, frame,
1126 : DPO_PROTO_IP6,
1127 : MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR));
1128 : }
1129 :
1130 183788 : 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 2302 : 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 2 : 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 183788 : 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 2300 : 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 0 : 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 183788 : 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 0 : mpls_label_dpo_mem_show (void)
1187 : {
1188 0 : fib_show_memory_usage("MPLS label",
1189 0 : pool_elts(mpls_label_dpo_pool),
1190 0 : pool_len(mpls_label_dpo_pool),
1191 : sizeof(mpls_label_dpo_t));
1192 0 : }
1193 :
1194 : /**
1195 : * Interpose a label DPO. used in the FIB unit tests
1196 : */
1197 : static void
1198 14 : 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 14 : mld_clone = mpls_label_dpo_alloc();
1205 14 : mld = mpls_label_dpo_get(original->dpoi_index);
1206 :
1207 14 : mld_clone->mld_locks = 0;
1208 14 : clib_memcpy_fast(&mld_clone->mld_hdr,
1209 14 : &mld->mld_hdr,
1210 : sizeof(mld_clone->mld_hdr));
1211 14 : mld_clone->mld_payload_proto = mld->mld_payload_proto;
1212 14 : mld_clone->mld_n_labels = mld->mld_n_labels;
1213 14 : mld_clone->mld_n_hdr_bytes = mld->mld_n_hdr_bytes;
1214 :
1215 14 : dpo_stack(mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1216 14 : mld_clone->mld_payload_proto,
1217 : &mld_clone->mld_dpo,
1218 : parent);
1219 :
1220 14 : dpo_set(clone,
1221 14 : mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE],
1222 14 : mld_clone->mld_payload_proto,
1223 : mpls_label_dpo_get_index(mld_clone));
1224 14 : }
1225 :
1226 : static u16
1227 0 : mpls_label_dpo_get_mtu (const dpo_id_t *dpo)
1228 : {
1229 : mpls_label_dpo_t *mld;
1230 :
1231 0 : 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 0 : 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 575 : mpls_label_dpo_module_init (void)
1341 : {
1342 575 : mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NONE] =
1343 575 : dpo_register_new_type(&mld_vft,
1344 : mpls_label_imp_pipe_nodes);
1345 575 : mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1346 575 : dpo_register_new_type(&mld_vft,
1347 : mpls_label_imp_pipe_no_ip_tll_decr_nodes);
1348 575 : mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE] =
1349 575 : dpo_register_new_type(&mld_vft,
1350 : mpls_label_imp_uniform_nodes);
1351 : mpls_label_dpo_types[MPLS_LABEL_DPO_FLAG_UNIFORM_MODE |
1352 575 : MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR] =
1353 575 : dpo_register_new_type(&mld_vft,
1354 : mpls_label_imp_uniform_no_ip_tll_decr_nodes);
1355 575 : }
1356 :
1357 : dpo_type_t
1358 65 : mpls_label_dpo_get_type (mpls_label_dpo_flags_t flags)
1359 : {
1360 65 : return (mpls_label_dpo_types[flags]);
1361 : }
1362 : #endif /* CLIB_MARCH_VARIANT */
1363 :
1364 : // clang-format on
|