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 : * ip/ip6_forward.c: IP v6 forwarding
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vnet/vnet.h>
41 : #include <vnet/ip/ip.h>
42 : #include <vnet/ip/ip_frag.h>
43 : #include <vnet/ip/ip6_link.h>
44 : #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
45 : #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46 : #include <vppinfra/cache.h>
47 : #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
48 : #include <vnet/fib/ip6_fib.h>
49 : #include <vnet/mfib/ip6_mfib.h>
50 : #include <vnet/dpo/load_balance_map.h>
51 : #include <vnet/dpo/receive_dpo.h>
52 : #include <vnet/dpo/classify_dpo.h>
53 : #include <vnet/classify/vnet_classify.h>
54 : #include <vnet/pg/pg.h>
55 :
56 : #ifndef CLIB_MARCH_VARIANT
57 : #include <vppinfra/bihash_template.c>
58 : #endif
59 : #include <vnet/ip/ip6_forward.h>
60 : #include <vnet/interface_output.h>
61 :
62 : /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
63 : #define OI_DECAP 0x80000000
64 :
65 : static void
66 2158 : ip6_add_interface_prefix_routes (ip6_main_t * im,
67 : u32 sw_if_index,
68 : u32 fib_index,
69 : ip6_address_t * address, u32 address_length)
70 : {
71 2158 : ip_lookup_main_t *lm = &im->lookup_main;
72 : ip_interface_prefix_t *if_prefix;
73 :
74 : /* *INDENT-OFF* */
75 2158 : ip_interface_prefix_key_t key = {
76 : .prefix = {
77 : .fp_len = address_length,
78 : .fp_proto = FIB_PROTOCOL_IP6,
79 : .fp_addr.ip6 = {
80 : .as_u64 = {
81 2158 : address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
82 2158 : address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
83 : },
84 : },
85 : },
86 : .sw_if_index = sw_if_index,
87 : };
88 : /* *INDENT-ON* */
89 :
90 : /* If prefix already set on interface, just increment ref count & return */
91 2158 : if_prefix = ip_get_interface_prefix (lm, &key);
92 2158 : if (if_prefix)
93 : {
94 11 : if_prefix->ref_count += 1;
95 11 : return;
96 : }
97 :
98 : /* New prefix - allocate a pool entry, initialize it, add to the hash */
99 2147 : pool_get (lm->if_prefix_pool, if_prefix);
100 2147 : if_prefix->ref_count = 1;
101 2147 : clib_memcpy (&if_prefix->key, &key, sizeof (key));
102 2147 : mhash_set (&lm->prefix_to_if_prefix_index, &key,
103 2147 : if_prefix - lm->if_prefix_pool, 0 /* old value */ );
104 :
105 : /* length < 128 - add glean */
106 2147 : if (address_length < 128)
107 : {
108 : /* set the glean route for the prefix */
109 2137 : fib_table_entry_update_one_path (fib_index, &key.prefix,
110 : FIB_SOURCE_INTERFACE,
111 : (FIB_ENTRY_FLAG_CONNECTED |
112 : FIB_ENTRY_FLAG_ATTACHED),
113 : DPO_PROTO_IP6,
114 : /* No next-hop address */
115 : NULL, sw_if_index,
116 : /* invalid FIB index */
117 : ~0, 1,
118 : /* no out-label stack */
119 : NULL, FIB_ROUTE_PATH_FLAG_NONE);
120 : }
121 : }
122 :
123 : static void
124 2158 : ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
125 : ip6_main_t * im, u32 fib_index,
126 : ip_interface_address_t * a)
127 : {
128 2158 : ip_lookup_main_t *lm = &im->lookup_main;
129 2158 : ip6_address_t *address = ip_interface_address_get_address (lm, a);
130 2158 : fib_prefix_t pfx = {
131 2158 : .fp_len = a->address_length,
132 : .fp_proto = FIB_PROTOCOL_IP6,
133 : .fp_addr.ip6 = *address,
134 : };
135 :
136 : /* set special routes for the prefix if needed */
137 2158 : ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
138 2158 : address, a->address_length);
139 :
140 2158 : pfx.fp_len = 128;
141 2158 : if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
142 : {
143 0 : u32 classify_table_index =
144 0 : lm->classify_table_index_by_sw_if_index[sw_if_index];
145 0 : if (classify_table_index != (u32) ~ 0)
146 : {
147 0 : dpo_id_t dpo = DPO_INVALID;
148 :
149 0 : dpo_set (&dpo,
150 : DPO_CLASSIFY,
151 : DPO_PROTO_IP6,
152 : classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
153 :
154 0 : fib_table_entry_special_dpo_add (fib_index,
155 : &pfx,
156 : FIB_SOURCE_CLASSIFY,
157 : FIB_ENTRY_FLAG_NONE, &dpo);
158 0 : dpo_reset (&dpo);
159 : }
160 : }
161 :
162 2158 : fib_table_entry_update_one_path (fib_index, &pfx,
163 : FIB_SOURCE_INTERFACE,
164 : (FIB_ENTRY_FLAG_CONNECTED |
165 : FIB_ENTRY_FLAG_LOCAL),
166 : DPO_PROTO_IP6,
167 : &pfx.fp_addr,
168 : sw_if_index, ~0,
169 : 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
170 2158 : }
171 :
172 : static void
173 1997 : ip6_del_interface_prefix_routes (ip6_main_t * im,
174 : u32 sw_if_index,
175 : u32 fib_index,
176 : ip6_address_t * address, u32 address_length)
177 : {
178 1997 : ip_lookup_main_t *lm = &im->lookup_main;
179 : ip_interface_prefix_t *if_prefix;
180 :
181 : /* *INDENT-OFF* */
182 1997 : ip_interface_prefix_key_t key = {
183 : .prefix = {
184 : .fp_len = address_length,
185 : .fp_proto = FIB_PROTOCOL_IP6,
186 : .fp_addr.ip6 = {
187 : .as_u64 = {
188 1997 : address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
189 1997 : address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
190 : },
191 : },
192 : },
193 : .sw_if_index = sw_if_index,
194 : };
195 : /* *INDENT-ON* */
196 :
197 1997 : if_prefix = ip_get_interface_prefix (lm, &key);
198 1997 : if (!if_prefix)
199 : {
200 0 : clib_warning ("Prefix not found while deleting %U",
201 : format_ip4_address_and_length, address, address_length);
202 11 : return;
203 : }
204 :
205 : /* If not deleting last intf addr in prefix, decrement ref count & return */
206 1997 : if_prefix->ref_count -= 1;
207 1997 : if (if_prefix->ref_count > 0)
208 11 : return;
209 :
210 : /* length <= 128, delete glean route */
211 1986 : if (address_length <= 128)
212 : {
213 : /* remove glean route for prefix */
214 1986 : fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
215 : }
216 :
217 1986 : mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
218 1986 : pool_put (lm->if_prefix_pool, if_prefix);
219 : }
220 :
221 : static void
222 1997 : ip6_del_interface_routes (u32 sw_if_index, ip6_main_t * im,
223 : u32 fib_index,
224 : ip6_address_t * address, u32 address_length)
225 : {
226 1997 : fib_prefix_t pfx = {
227 : .fp_len = 128,
228 : .fp_proto = FIB_PROTOCOL_IP6,
229 : .fp_addr.ip6 = *address,
230 : };
231 :
232 : /* delete special routes for the prefix if needed */
233 1997 : ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
234 : address, address_length);
235 :
236 1997 : fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
237 1997 : }
238 :
239 : #ifndef CLIB_MARCH_VARIANT
240 : void
241 8244 : ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
242 : {
243 8244 : ip6_main_t *im = &ip6_main;
244 8244 : vnet_main_t *vnm = vnet_get_main ();
245 8244 : vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
246 :
247 9830 : vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
248 :
249 : /*
250 : * enable/disable only on the 1<->0 transition
251 : */
252 8244 : if (is_enable)
253 : {
254 4296 : if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
255 2142 : return;
256 : }
257 : else
258 : {
259 : /* The ref count is 0 when an address is removed from an interface that has
260 : * no address - this is not a ciritical error */
261 3948 : if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
262 3948 : 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
263 1974 : return;
264 : }
265 :
266 4128 : vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
267 : !is_enable, 0, 0);
268 :
269 4128 : vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
270 : sw_if_index, !is_enable, 0, 0);
271 :
272 4128 : if (is_enable)
273 2154 : hi->l3_if_count++;
274 1974 : else if (hi->l3_if_count)
275 1974 : hi->l3_if_count--;
276 : }
277 :
278 : /* get first interface address */
279 : ip6_address_t *
280 23 : ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
281 : {
282 23 : ip_lookup_main_t *lm = &im->lookup_main;
283 23 : ip_interface_address_t *ia = 0;
284 23 : ip6_address_t *result = 0;
285 :
286 : /* *INDENT-OFF* */
287 23 : foreach_ip_interface_address (lm, ia, sw_if_index,
288 : 1 /* honor unnumbered */,
289 : ({
290 : ip6_address_t * a = ip_interface_address_get_address (lm, ia);
291 : result = a;
292 : break;
293 : }));
294 : /* *INDENT-ON* */
295 23 : return result;
296 : }
297 :
298 : clib_error_t *
299 4127 : ip6_add_del_interface_address (vlib_main_t * vm,
300 : u32 sw_if_index,
301 : ip6_address_t * address,
302 : u32 address_length, u32 is_del)
303 : {
304 4127 : vnet_main_t *vnm = vnet_get_main ();
305 4127 : ip6_main_t *im = &ip6_main;
306 4127 : ip_lookup_main_t *lm = &im->lookup_main;
307 4127 : clib_error_t *error = NULL;
308 : u32 if_address_index;
309 4127 : ip6_address_fib_t ip6_af, *addr_fib = 0;
310 : const ip6_address_t *ll_addr;
311 :
312 4127 : error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
313 4127 : if (error)
314 : {
315 0 : vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
316 0 : return error;
317 : }
318 :
319 4127 : if (ip6_address_is_link_local_unicast (address))
320 : {
321 5 : if (address_length != 128)
322 : {
323 0 : vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
324 : return
325 0 : clib_error_create
326 : ("prefix length of link-local address must be 128");
327 : }
328 5 : if (!is_del)
329 : {
330 : int rv;
331 :
332 4 : rv = ip6_link_set_local_address (sw_if_index, address);
333 :
334 4 : if (rv)
335 : {
336 0 : vnm->api_errno = rv;
337 0 : return clib_error_create ("address not assignable");
338 : }
339 : }
340 : else
341 : {
342 1 : ll_addr = ip6_get_link_local_address (sw_if_index);
343 1 : if (ip6_address_is_equal (ll_addr, address))
344 : {
345 1 : vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
346 1 : return clib_error_create ("address not deletable");
347 : }
348 : else
349 : {
350 0 : vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
351 0 : return clib_error_create ("address not found");
352 : }
353 : }
354 :
355 4 : return (NULL);
356 : }
357 :
358 4122 : ip6_addr_fib_init (&ip6_af, address,
359 4122 : vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
360 4122 : vec_add1 (addr_fib, ip6_af);
361 :
362 : /* *INDENT-OFF* */
363 4122 : if (!is_del)
364 : {
365 : /* When adding an address check that it does not conflict
366 : with an existing address on any interface in this table. */
367 : ip_interface_address_t *ia;
368 : vnet_sw_interface_t *sif;
369 :
370 12741 : pool_foreach (sif, vnm->interface_main.sw_interfaces)
371 : {
372 10594 : if (im->fib_index_by_sw_if_index[sw_if_index] ==
373 10594 : im->fib_index_by_sw_if_index[sif->sw_if_index])
374 : {
375 12177 : foreach_ip_interface_address
376 : (&im->lookup_main, ia, sif->sw_if_index,
377 : 0 /* honor unnumbered */ ,
378 : ({
379 : ip6_address_t * x =
380 : ip_interface_address_get_address
381 : (&im->lookup_main, ia);
382 :
383 : if (ip6_destination_matches_route
384 : (im, address, x, ia->address_length) ||
385 : ip6_destination_matches_route (im,
386 : x,
387 : address,
388 : address_length))
389 : {
390 : /* an intf may have >1 addr from the same prefix */
391 : if ((sw_if_index == sif->sw_if_index) &&
392 : (ia->address_length == address_length) &&
393 : !ip6_address_is_equal (x, address))
394 : continue;
395 :
396 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
397 : /* if the address we're comparing against is stale
398 : * then the CP has not added this one back yet, maybe
399 : * it never will, so we have to assume it won't and
400 : * ignore it. if it does add it back, then it will fail
401 : * because this one is now present */
402 : continue;
403 :
404 : /* error if the length or intf was different */
405 : vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
406 : error = clib_error_create
407 : ("failed to add %U which conflicts with %U for interface %U",
408 : format_ip6_address_and_length, address,
409 : address_length,
410 : format_ip6_address_and_length, x,
411 : ia->address_length,
412 : format_vnet_sw_if_index_name, vnm,
413 : sif->sw_if_index);
414 : goto done;
415 : }
416 : }));
417 : }
418 : }
419 : }
420 : /* *INDENT-ON* */
421 :
422 4122 : if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
423 :
424 4122 : if (is_del)
425 : {
426 1975 : if (~0 == if_address_index)
427 : {
428 0 : vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
429 0 : error = clib_error_create ("%U not found for interface %U",
430 : lm->format_address_and_length,
431 : addr_fib, address_length,
432 : format_vnet_sw_if_index_name, vnm,
433 : sw_if_index);
434 0 : goto done;
435 : }
436 :
437 1975 : error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
438 : address_length, sw_if_index);
439 1975 : if (error)
440 1 : goto done;
441 : }
442 : else
443 : {
444 2147 : if (~0 != if_address_index)
445 : {
446 : ip_interface_address_t *ia;
447 :
448 9 : ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
449 :
450 9 : if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
451 : {
452 9 : if (ia->sw_if_index == sw_if_index)
453 : {
454 : /* re-adding an address during the replace action.
455 : * consdier this the update. clear the flag and
456 : * we're done */
457 6 : ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
458 6 : goto done;
459 : }
460 : else
461 : {
462 : /* The prefix is moving from one interface to another.
463 : * delete the stale and add the new */
464 3 : ip6_add_del_interface_address (vm,
465 : ia->sw_if_index,
466 : address, address_length, 1);
467 3 : ia = NULL;
468 3 : error = ip_interface_address_add (lm, sw_if_index,
469 : addr_fib, address_length,
470 : &if_address_index);
471 : }
472 : }
473 : else
474 : {
475 0 : vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
476 0 : error = clib_error_create
477 : ("Prefix %U already found on interface %U",
478 : lm->format_address_and_length, addr_fib, address_length,
479 : format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
480 : }
481 : }
482 : else
483 2138 : error = ip_interface_address_add (lm, sw_if_index,
484 : addr_fib, address_length,
485 : &if_address_index);
486 : }
487 :
488 4115 : if (error)
489 0 : goto done;
490 :
491 4115 : ip6_sw_interface_enable_disable (sw_if_index, !is_del);
492 4115 : if (!is_del)
493 2141 : ip6_link_enable (sw_if_index, NULL);
494 :
495 : /* intf addr routes are added/deleted on admin up/down */
496 4115 : if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
497 : {
498 2867 : if (is_del)
499 805 : ip6_del_interface_routes (sw_if_index,
500 : im, ip6_af.fib_index, address,
501 : address_length);
502 : else
503 2062 : ip6_add_interface_routes (vnm, sw_if_index,
504 : im, ip6_af.fib_index,
505 2062 : pool_elt_at_index (lm->if_address_pool,
506 : if_address_index));
507 : }
508 :
509 : ip6_add_del_interface_address_callback_t *cb;
510 20587 : vec_foreach (cb, im->add_del_interface_address_callbacks)
511 16472 : cb->function (im, cb->function_opaque, sw_if_index,
512 : address, address_length, if_address_index, is_del);
513 :
514 4115 : if (is_del)
515 1974 : ip6_link_disable (sw_if_index);
516 :
517 2141 : done:
518 4122 : vec_free (addr_fib);
519 4122 : return error;
520 : }
521 :
522 : #endif
523 :
524 : static clib_error_t *
525 13514 : ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
526 : {
527 13514 : ip6_main_t *im = &ip6_main;
528 : ip_interface_address_t *ia;
529 : ip6_address_t *a;
530 : u32 is_admin_up, fib_index;
531 :
532 13514 : vec_validate_init_empty (im->
533 : lookup_main.if_address_pool_index_by_sw_if_index,
534 : sw_if_index, ~0);
535 :
536 13514 : is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
537 :
538 13514 : fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
539 :
540 : /* *INDENT-OFF* */
541 14802 : foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
542 : 0 /* honor unnumbered */,
543 : ({
544 : a = ip_interface_address_get_address (&im->lookup_main, ia);
545 : if (is_admin_up)
546 : ip6_add_interface_routes (vnm, sw_if_index,
547 : im, fib_index,
548 : ia);
549 : else
550 : ip6_del_interface_routes (sw_if_index, im, fib_index,
551 : a, ia->address_length);
552 : }));
553 : /* *INDENT-ON* */
554 :
555 13514 : return 0;
556 : }
557 :
558 2881 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
559 :
560 : /* Built-in ip6 unicast rx feature path definition */
561 : /* *INDENT-OFF* */
562 1151 : VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
563 : {
564 : .arc_name = "ip6-unicast",
565 : .start_nodes = VNET_FEATURES ("ip6-input"),
566 : .last_in_arc = "ip6-lookup",
567 : .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
568 : };
569 :
570 76635 : VNET_FEATURE_INIT (ip6_flow_classify, static) =
571 : {
572 : .arc_name = "ip6-unicast",
573 : .node_name = "ip6-flow-classify",
574 : .runs_before = VNET_FEATURES ("ip6-inacl"),
575 : };
576 :
577 76635 : VNET_FEATURE_INIT (ip6_inacl, static) =
578 : {
579 : .arc_name = "ip6-unicast",
580 : .node_name = "ip6-inacl",
581 : .runs_before = VNET_FEATURES ("ip6-policer-classify"),
582 : };
583 :
584 76635 : VNET_FEATURE_INIT (ip6_policer_classify, static) =
585 : {
586 : .arc_name = "ip6-unicast",
587 : .node_name = "ip6-policer-classify",
588 : .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
589 : };
590 :
591 76635 : VNET_FEATURE_INIT (ip6_ipsec, static) =
592 : {
593 : .arc_name = "ip6-unicast",
594 : .node_name = "ipsec6-input-feature",
595 : .runs_before = VNET_FEATURES ("l2tp-decap"),
596 : };
597 :
598 76635 : VNET_FEATURE_INIT (ip6_l2tp, static) =
599 : {
600 : .arc_name = "ip6-unicast",
601 : .node_name = "l2tp-decap",
602 : .runs_before = VNET_FEATURES ("vpath-input-ip6"),
603 : };
604 :
605 76635 : VNET_FEATURE_INIT (ip6_vpath, static) =
606 : {
607 : .arc_name = "ip6-unicast",
608 : .node_name = "vpath-input-ip6",
609 : .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
610 : };
611 :
612 76635 : VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
613 : {
614 : .arc_name = "ip6-unicast",
615 : .node_name = "ip6-vxlan-bypass",
616 : .runs_before = VNET_FEATURES ("ip6-lookup"),
617 : };
618 :
619 76635 : VNET_FEATURE_INIT (ip6_not_enabled, static) =
620 : {
621 : .arc_name = "ip6-unicast",
622 : .node_name = "ip6-not-enabled",
623 : .runs_before = VNET_FEATURES ("ip6-lookup"),
624 : };
625 :
626 76635 : VNET_FEATURE_INIT (ip6_lookup, static) =
627 : {
628 : .arc_name = "ip6-unicast",
629 : .node_name = "ip6-lookup",
630 : .runs_before = 0, /*last feature*/
631 : };
632 :
633 : /* Built-in ip6 multicast rx feature path definition (none now) */
634 1151 : VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
635 : {
636 : .arc_name = "ip6-multicast",
637 : .start_nodes = VNET_FEATURES ("ip6-input"),
638 : .last_in_arc = "ip6-mfib-forward-lookup",
639 : .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
640 : };
641 :
642 76635 : VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
643 : .arc_name = "ip6-multicast",
644 : .node_name = "vpath-input-ip6",
645 : .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
646 : };
647 :
648 76635 : VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
649 : .arc_name = "ip6-multicast",
650 : .node_name = "ip6-not-enabled",
651 : .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
652 : };
653 :
654 76635 : VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
655 : .arc_name = "ip6-multicast",
656 : .node_name = "ip6-mfib-forward-lookup",
657 : .runs_before = 0, /* last feature */
658 : };
659 :
660 : /* Built-in ip4 tx feature path definition */
661 1151 : VNET_FEATURE_ARC_INIT (ip6_output, static) =
662 : {
663 : .arc_name = "ip6-output",
664 : .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
665 : .last_in_arc = "interface-output",
666 : .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
667 : };
668 :
669 76635 : VNET_FEATURE_INIT (ip6_outacl, static) = {
670 : .arc_name = "ip6-output",
671 : .node_name = "ip6-outacl",
672 : .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
673 : };
674 :
675 76635 : VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
676 : .arc_name = "ip6-output",
677 : .node_name = "ipsec6-output-feature",
678 : .runs_before = VNET_FEATURES ("interface-output"),
679 : };
680 :
681 76635 : VNET_FEATURE_INIT (ip6_interface_output, static) = {
682 : .arc_name = "ip6-output",
683 : .node_name = "interface-output",
684 : .runs_before = 0, /* not before any other features */
685 : };
686 : /* *INDENT-ON* */
687 :
688 : static clib_error_t *
689 11798 : ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
690 : {
691 11798 : ip6_main_t *im = &ip6_main;
692 :
693 15752 : vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
694 15752 : vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
695 :
696 11798 : if (is_add)
697 : {
698 : /* Fill in lookup tables with default table (0). */
699 7547 : im->fib_index_by_sw_if_index[sw_if_index] = 0;
700 7547 : im->mfib_index_by_sw_if_index[sw_if_index] = 0;
701 : }
702 : else
703 : {
704 : /* Ensure that IPv6 is disabled */
705 4251 : ip6_main_t *im6 = &ip6_main;
706 4251 : ip_lookup_main_t *lm6 = &im6->lookup_main;
707 4251 : ip_interface_address_t *ia = 0;
708 : ip6_address_t *address;
709 4251 : vlib_main_t *vm = vlib_get_main ();
710 :
711 4251 : vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
712 : /* *INDENT-OFF* */
713 4251 : foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
714 : ({
715 : address = ip_interface_address_get_address (lm6, ia);
716 : ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
717 : }));
718 : /* *INDENT-ON* */
719 4251 : ip6_mfib_interface_enable_disable (sw_if_index, 0);
720 :
721 4251 : if (0 != im6->fib_index_by_sw_if_index[sw_if_index])
722 109 : fib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0);
723 4251 : if (0 != im6->mfib_index_by_sw_if_index[sw_if_index])
724 108 : mfib_table_bind (FIB_PROTOCOL_IP6, sw_if_index, 0);
725 :
726 : /* Erase the lookup tables just in case */
727 4251 : im6->fib_index_by_sw_if_index[sw_if_index] = ~0;
728 4251 : im6->mfib_index_by_sw_if_index[sw_if_index] = ~0;
729 : }
730 :
731 11798 : vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
732 : is_add, 0, 0);
733 :
734 11798 : vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
735 : sw_if_index, is_add, 0, 0);
736 :
737 11798 : return /* no error */ 0;
738 : }
739 :
740 3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
741 :
742 232002 : VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
743 : vlib_node_runtime_t * node,
744 : vlib_frame_t * frame)
745 : {
746 229702 : return ip6_lookup_inline (vm, node, frame);
747 : }
748 :
749 : static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
750 :
751 : /* *INDENT-OFF* */
752 183788 : VLIB_REGISTER_NODE (ip6_lookup_node) =
753 : {
754 : .name = "ip6-lookup",
755 : .vector_size = sizeof (u32),
756 : .format_trace = format_ip6_lookup_trace,
757 : .n_next_nodes = IP6_LOOKUP_N_NEXT,
758 : .next_nodes = IP6_LOOKUP_NEXT_NODES,
759 : };
760 : /* *INDENT-ON* */
761 :
762 3616 : VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
763 : vlib_node_runtime_t * node,
764 : vlib_frame_t * frame)
765 : {
766 1316 : vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
767 : u32 n_left, *from;
768 1316 : u32 thread_index = vm->thread_index;
769 1316 : ip6_main_t *im = &ip6_main;
770 1316 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
771 : u16 nexts[VLIB_FRAME_SIZE], *next;
772 :
773 1316 : from = vlib_frame_vector_args (frame);
774 1316 : n_left = frame->n_vectors;
775 1316 : next = nexts;
776 :
777 1316 : vlib_get_buffers (vm, from, bufs, n_left);
778 :
779 37069 : while (n_left >= 4)
780 : {
781 : const load_balance_t *lb0, *lb1;
782 : const ip6_header_t *ip0, *ip1;
783 : u32 lbi0, hc0, lbi1, hc1;
784 : const dpo_id_t *dpo0, *dpo1;
785 :
786 : /* Prefetch next iteration. */
787 : {
788 35753 : vlib_prefetch_buffer_header (b[2], STORE);
789 35753 : vlib_prefetch_buffer_header (b[3], STORE);
790 :
791 35753 : CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
792 35753 : CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
793 : }
794 :
795 35753 : ip0 = vlib_buffer_get_current (b[0]);
796 35753 : ip1 = vlib_buffer_get_current (b[1]);
797 35753 : lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
798 35753 : lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
799 :
800 35753 : lb0 = load_balance_get (lbi0);
801 35753 : lb1 = load_balance_get (lbi1);
802 :
803 : /*
804 : * this node is for via FIBs we can re-use the hash value from the
805 : * to node if present.
806 : * We don't want to use the same hash value at each level in the recursion
807 : * graph as that would lead to polarisation
808 : */
809 35753 : hc0 = hc1 = 0;
810 :
811 35753 : if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
812 : {
813 254 : if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
814 : {
815 254 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
816 254 : vnet_buffer (b[0])->ip.flow_hash >> 1;
817 : }
818 : else
819 : {
820 0 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
821 0 : ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
822 : }
823 254 : dpo0 = load_balance_get_fwd_bucket
824 254 : (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
825 : }
826 : else
827 : {
828 35499 : dpo0 = load_balance_get_bucket_i (lb0, 0);
829 : }
830 35753 : if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
831 : {
832 254 : if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
833 : {
834 254 : hc1 = vnet_buffer (b[1])->ip.flow_hash =
835 254 : vnet_buffer (b[1])->ip.flow_hash >> 1;
836 : }
837 : else
838 : {
839 0 : hc1 = vnet_buffer (b[1])->ip.flow_hash =
840 0 : ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
841 : }
842 254 : dpo1 = load_balance_get_fwd_bucket
843 254 : (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
844 : }
845 : else
846 : {
847 35499 : dpo1 = load_balance_get_bucket_i (lb1, 0);
848 : }
849 :
850 35753 : next[0] = dpo0->dpoi_next_node;
851 35753 : next[1] = dpo1->dpoi_next_node;
852 :
853 : /* Only process the HBH Option Header if explicitly configured to do so */
854 35753 : if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
855 : {
856 0 : next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
857 : (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
858 : }
859 : /* Only process the HBH Option Header if explicitly configured to do so */
860 35753 : if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
861 : {
862 0 : next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
863 : (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
864 : }
865 :
866 35753 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
867 35753 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
868 :
869 35753 : vlib_increment_combined_counter
870 : (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
871 35753 : vlib_increment_combined_counter
872 35753 : (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
873 :
874 35753 : b += 2;
875 35753 : next += 2;
876 35753 : n_left -= 2;
877 : }
878 :
879 4989 : while (n_left > 0)
880 : {
881 : const load_balance_t *lb0;
882 : const ip6_header_t *ip0;
883 : const dpo_id_t *dpo0;
884 : u32 lbi0, hc0;
885 :
886 3673 : ip0 = vlib_buffer_get_current (b[0]);
887 3673 : lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
888 :
889 3673 : lb0 = load_balance_get (lbi0);
890 :
891 3673 : hc0 = 0;
892 3673 : if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
893 : {
894 6 : if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
895 : {
896 6 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
897 6 : vnet_buffer (b[0])->ip.flow_hash >> 1;
898 : }
899 : else
900 : {
901 0 : hc0 = vnet_buffer (b[0])->ip.flow_hash =
902 0 : ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
903 : }
904 6 : dpo0 = load_balance_get_fwd_bucket
905 6 : (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
906 : }
907 : else
908 : {
909 3667 : dpo0 = load_balance_get_bucket_i (lb0, 0);
910 : }
911 :
912 3673 : next[0] = dpo0->dpoi_next_node;
913 3673 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
914 :
915 : /* Only process the HBH Option Header if explicitly configured to do so */
916 3673 : if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
917 : {
918 0 : next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
919 : (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
920 : }
921 :
922 3673 : vlib_increment_combined_counter
923 : (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
924 :
925 3673 : b += 1;
926 3673 : next += 1;
927 3673 : n_left -= 1;
928 : }
929 :
930 1316 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
931 :
932 1316 : if (node->flags & VLIB_NODE_FLAG_TRACE)
933 1116 : ip6_forward_next_trace (vm, node, frame, VLIB_TX);
934 :
935 1316 : return frame->n_vectors;
936 : }
937 :
938 : /* *INDENT-OFF* */
939 183788 : VLIB_REGISTER_NODE (ip6_load_balance_node) =
940 : {
941 : .name = "ip6-load-balance",
942 : .vector_size = sizeof (u32),
943 : .sibling_of = "ip6-lookup",
944 : .format_trace = format_ip6_lookup_trace,
945 : };
946 : /* *INDENT-ON* */
947 :
948 : typedef struct
949 : {
950 : /* Adjacency taken. */
951 : u32 adj_index;
952 : u32 flow_hash;
953 : u32 fib_index;
954 :
955 : /* Packet data, possibly *after* rewrite. */
956 : u8 packet_data[128 - 1 * sizeof (u32)];
957 : }
958 : ip6_forward_next_trace_t;
959 :
960 : #ifndef CLIB_MARCH_VARIANT
961 : u8 *
962 47361 : format_ip6_forward_next_trace (u8 * s, va_list * args)
963 : {
964 47361 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
965 47361 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
966 47361 : ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
967 47361 : u32 indent = format_get_indent (s);
968 :
969 47361 : s = format (s, "%Ufib:%d adj:%d flow:%d",
970 : format_white_space, indent,
971 : t->fib_index, t->adj_index, t->flow_hash);
972 47361 : s = format (s, "\n%U%U",
973 : format_white_space, indent,
974 47361 : format_ip6_header, t->packet_data, sizeof (t->packet_data));
975 47361 : return s;
976 : }
977 : #endif
978 :
979 : static u8 *
980 173784 : format_ip6_lookup_trace (u8 * s, va_list * args)
981 : {
982 173784 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
983 173784 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
984 173784 : ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
985 173784 : u32 indent = format_get_indent (s);
986 :
987 173784 : s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
988 : t->fib_index, t->adj_index, t->flow_hash);
989 173784 : s = format (s, "\n%U%U",
990 : format_white_space, indent,
991 173784 : format_ip6_header, t->packet_data, sizeof (t->packet_data));
992 173784 : return s;
993 : }
994 :
995 :
996 : static u8 *
997 112898 : format_ip6_rewrite_trace (u8 * s, va_list * args)
998 : {
999 112898 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1000 112898 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1001 112898 : ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
1002 112898 : u32 indent = format_get_indent (s);
1003 :
1004 112898 : s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1005 : t->fib_index, t->adj_index, format_ip_adjacency,
1006 : t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
1007 112898 : s = format (s, "\n%U%U",
1008 : format_white_space, indent,
1009 : format_ip_adjacency_packet_data,
1010 112898 : t->packet_data, sizeof (t->packet_data));
1011 112898 : return s;
1012 : }
1013 :
1014 : /* Common trace function for all ip6-forward next nodes. */
1015 : #ifndef CLIB_MARCH_VARIANT
1016 : void
1017 10156 : ip6_forward_next_trace (vlib_main_t * vm,
1018 : vlib_node_runtime_t * node,
1019 : vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1020 : {
1021 : u32 *from, n_left;
1022 10156 : ip6_main_t *im = &ip6_main;
1023 :
1024 10156 : n_left = frame->n_vectors;
1025 10156 : from = vlib_frame_vector_args (frame);
1026 :
1027 245126 : while (n_left >= 4)
1028 : {
1029 : u32 bi0, bi1;
1030 : vlib_buffer_t *b0, *b1;
1031 : ip6_forward_next_trace_t *t0, *t1;
1032 :
1033 : /* Prefetch next iteration. */
1034 234970 : vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1035 234970 : vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1036 :
1037 234970 : bi0 = from[0];
1038 234970 : bi1 = from[1];
1039 :
1040 234970 : b0 = vlib_get_buffer (vm, bi0);
1041 234970 : b1 = vlib_get_buffer (vm, bi1);
1042 :
1043 234970 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
1044 : {
1045 234541 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1046 234541 : t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1047 234541 : t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1048 234541 : t0->fib_index =
1049 234541 : (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1050 234541 : (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1051 137722 : vec_elt (im->fib_index_by_sw_if_index,
1052 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1053 :
1054 234541 : clib_memcpy_fast (t0->packet_data,
1055 234541 : vlib_buffer_get_current (b0),
1056 : sizeof (t0->packet_data));
1057 : }
1058 234970 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
1059 : {
1060 234540 : t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1061 234540 : t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1062 234540 : t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1063 234540 : t1->fib_index =
1064 234540 : (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1065 234540 : (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1066 137721 : vec_elt (im->fib_index_by_sw_if_index,
1067 : vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1068 :
1069 234540 : clib_memcpy_fast (t1->packet_data,
1070 234540 : vlib_buffer_get_current (b1),
1071 : sizeof (t1->packet_data));
1072 : }
1073 234970 : from += 2;
1074 234970 : n_left -= 2;
1075 : }
1076 :
1077 33588 : while (n_left >= 1)
1078 : {
1079 : u32 bi0;
1080 : vlib_buffer_t *b0;
1081 : ip6_forward_next_trace_t *t0;
1082 :
1083 23431 : bi0 = from[0];
1084 :
1085 23431 : b0 = vlib_get_buffer (vm, bi0);
1086 :
1087 23431 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
1088 : {
1089 23273 : t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1090 23274 : t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1091 23274 : t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1092 23274 : t0->fib_index =
1093 23274 : (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1094 23274 : (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1095 13864 : vec_elt (im->fib_index_by_sw_if_index,
1096 : vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1097 :
1098 23274 : clib_memcpy_fast (t0->packet_data,
1099 23274 : vlib_buffer_get_current (b0),
1100 : sizeof (t0->packet_data));
1101 : }
1102 23432 : from += 1;
1103 23432 : n_left -= 1;
1104 : }
1105 10157 : }
1106 :
1107 : /* Compute TCP/UDP/ICMP6 checksum in software. */
1108 : u16
1109 10843700 : ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1110 : ip6_header_t * ip0, int *bogus_lengthp)
1111 : {
1112 10843700 : ip_csum_t sum0 = 0;
1113 : u16 payload_length, payload_length_host_byte_order;
1114 : u32 i;
1115 10843700 : u32 headers_size = sizeof (ip0[0]);
1116 : u8 *data_this_buffer;
1117 10843700 : u8 next_hdr = ip0->protocol;
1118 :
1119 10843700 : ASSERT (bogus_lengthp);
1120 10843700 : *bogus_lengthp = 0;
1121 :
1122 10843700 : payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1123 10843700 : data_this_buffer = (u8 *) (ip0 + 1);
1124 10843700 : payload_length = ip0->payload_length;
1125 :
1126 : /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1127 : * or UDP-Ping packets */
1128 10843700 : if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1129 : {
1130 : u32 skip_bytes;
1131 1794 : ip6_hop_by_hop_ext_t *ext_hdr =
1132 : (ip6_hop_by_hop_ext_t *) data_this_buffer;
1133 :
1134 : /* validate really icmp6 next */
1135 1794 : ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1136 : || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
1137 :
1138 1794 : skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1139 1794 : data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
1140 :
1141 1794 : payload_length_host_byte_order -= skip_bytes;
1142 1794 : headers_size += skip_bytes;
1143 :
1144 : /* pseudo-header adjustments:
1145 : * exclude ext header bytes from payload length
1146 : * use payload IP proto rather than ext header IP proto
1147 : */
1148 1794 : payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1149 1794 : next_hdr = ext_hdr->next_hdr;
1150 : }
1151 :
1152 : /* Initialize checksum with ip pseudo-header. */
1153 10843700 : sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1154 :
1155 32531200 : for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1156 : {
1157 21687400 : sum0 = ip_csum_with_carry
1158 21687400 : (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1159 21687400 : sum0 = ip_csum_with_carry
1160 21687400 : (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
1161 : }
1162 :
1163 10843700 : if (p0)
1164 10843600 : return ip_calculate_l4_checksum (vm, p0, sum0,
1165 : payload_length_host_byte_order,
1166 : (u8 *) ip0, headers_size, NULL);
1167 : else
1168 150 : return ip_calculate_l4_checksum (vm, 0, sum0,
1169 : payload_length_host_byte_order, NULL, 0,
1170 : data_this_buffer);
1171 : }
1172 :
1173 : u32
1174 10515400 : ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1175 : {
1176 10515400 : ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1177 : udp_header_t *udp0;
1178 : u16 sum16;
1179 : int bogus_length;
1180 :
1181 : /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1182 10515400 : ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1183 : || ip0->protocol == IP_PROTOCOL_ICMP6
1184 : || ip0->protocol == IP_PROTOCOL_UDP
1185 : || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
1186 :
1187 10515400 : udp0 = (void *) (ip0 + 1);
1188 10515400 : if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1189 : {
1190 0 : p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1191 : | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1192 0 : return p0->flags;
1193 : }
1194 :
1195 10515400 : sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1196 :
1197 21030700 : p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1198 10515400 : | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1199 :
1200 10515400 : return p0->flags;
1201 : }
1202 : #endif
1203 :
1204 : /**
1205 : * @brief returns number of links on which src is reachable.
1206 : */
1207 : always_inline int
1208 25686 : ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1209 : {
1210 : const load_balance_t *lb0;
1211 : index_t lbi;
1212 : u32 fib_index;
1213 :
1214 25686 : fib_index = vec_elt (im->fib_index_by_sw_if_index,
1215 : vnet_buffer (b)->sw_if_index[VLIB_RX]);
1216 25686 : fib_index =
1217 25686 : (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1218 25686 : fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
1219 :
1220 25686 : lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
1221 25686 : lb0 = load_balance_get (lbi);
1222 :
1223 25686 : return (fib_urpf_check_size (lb0->lb_urpf));
1224 : }
1225 :
1226 : always_inline u8
1227 60615 : ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1228 : u32 * udp_offset0)
1229 : {
1230 60615 : int nh = ip6_locate_header (p0, ip0, -1, udp_offset0);
1231 60615 : if (nh > 0)
1232 60613 : if (nh == IP_PROTOCOL_UDP || nh == IP_PROTOCOL_TCP)
1233 13523 : return nh;
1234 47092 : return 0;
1235 : }
1236 :
1237 : /* *INDENT-OFF* */
1238 1151 : VNET_FEATURE_ARC_INIT (ip6_local) = {
1239 : .arc_name = "ip6-local",
1240 : .start_nodes = VNET_FEATURES ("ip6-local", "ip6-receive"),
1241 : };
1242 : /* *INDENT-ON* */
1243 :
1244 : static_always_inline u8
1245 18538 : ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
1246 : {
1247 :
1248 : u16 payload_length_host_byte_order;
1249 : u32 n_this_buffer, n_bytes_left;
1250 18538 : ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1251 18538 : u32 headers_size = sizeof (ip0[0]);
1252 : u8 *data_this_buffer;
1253 :
1254 :
1255 18538 : data_this_buffer = (u8 *) (ip0 + 1);
1256 :
1257 18538 : ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1258 :
1259 : /* validate really icmp6 next */
1260 :
1261 18538 : if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1262 255 : || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1263 18283 : return 0;
1264 :
1265 :
1266 255 : payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1267 255 : n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1268 :
1269 :
1270 255 : u32 n_ip_bytes_this_buffer =
1271 255 : p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1272 255 : if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
1273 : {
1274 0 : n_this_buffer = p0->current_length > headers_size ?
1275 0 : n_ip_bytes_this_buffer - headers_size : 0;
1276 : }
1277 :
1278 255 : n_bytes_left -= n_this_buffer;
1279 255 : n_bytes_left -= vlib_buffer_length_in_chain (vm, p0) - p0->current_length;
1280 :
1281 255 : if (n_bytes_left == 0)
1282 255 : return 0;
1283 : else
1284 0 : return 1;
1285 : }
1286 :
1287 : always_inline uword
1288 3249 : ip6_local_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
1289 : vlib_frame_t *frame, int head_of_feature_arc,
1290 : int is_receive_dpo)
1291 : {
1292 3249 : ip6_main_t *im = &ip6_main;
1293 3249 : ip_lookup_main_t *lm = &im->lookup_main;
1294 : u32 *from, n_left_from;
1295 : vlib_node_runtime_t *error_node =
1296 3249 : vlib_node_get_runtime (vm, ip6_input_node.index);
1297 3249 : u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
1298 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1299 : u16 nexts[VLIB_FRAME_SIZE], *next;
1300 :
1301 3249 : from = vlib_frame_vector_args (frame);
1302 3249 : n_left_from = frame->n_vectors;
1303 :
1304 3249 : if (node->flags & VLIB_NODE_FLAG_TRACE)
1305 2505 : ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1306 :
1307 3249 : vlib_get_buffers (vm, from, bufs, n_left_from);
1308 3249 : b = bufs;
1309 3249 : next = nexts;
1310 :
1311 31786 : while (n_left_from > 2)
1312 : {
1313 : /* Prefetch next iteration. */
1314 28537 : if (n_left_from >= 6)
1315 : {
1316 27234 : vlib_prefetch_buffer_header (b[4], STORE);
1317 27234 : vlib_prefetch_buffer_header (b[5], STORE);
1318 27234 : vlib_prefetch_buffer_data (b[2], LOAD);
1319 27234 : vlib_prefetch_buffer_data (b[3], LOAD);
1320 : }
1321 :
1322 : vl_counter_ip6_enum_t error[2];
1323 28537 : error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1324 28537 : error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1325 :
1326 : ip6_header_t *ip[2];
1327 28537 : ip[0] = vlib_buffer_get_current (b[0]);
1328 28537 : ip[1] = vlib_buffer_get_current (b[1]);
1329 :
1330 28537 : if (head_of_feature_arc)
1331 : {
1332 28537 : vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1333 28537 : vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1334 :
1335 : u8 type[2];
1336 28537 : type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1337 28537 : type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
1338 :
1339 : u32 flags[2];
1340 28537 : flags[0] = b[0]->flags;
1341 28537 : flags[1] = b[1]->flags;
1342 :
1343 : vnet_buffer_oflags_t oflags[2];
1344 28537 : oflags[0] = vnet_buffer (b[0])->oflags;
1345 28537 : oflags[1] = vnet_buffer (b[1])->oflags;
1346 :
1347 : u32 l4_offload[2];
1348 28537 : l4_offload[0] = (flags[0] & VNET_BUFFER_F_OFFLOAD) &&
1349 0 : (oflags[0] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1350 : VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1351 28537 : l4_offload[1] = (flags[1] & VNET_BUFFER_F_OFFLOAD) &&
1352 0 : (oflags[1] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1353 : VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1354 :
1355 : u32 good_l4_csum[2];
1356 28537 : good_l4_csum[0] =
1357 28537 : (flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[0];
1358 28537 : good_l4_csum[1] =
1359 28537 : (flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[1];
1360 :
1361 28537 : u32 udp_offset[2] = { };
1362 : u8 is_tcp_udp[2];
1363 28537 : is_tcp_udp[0] =
1364 28537 : ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1365 28537 : is_tcp_udp[1] =
1366 28537 : ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1367 28537 : i16 len_diff[2] = { 0 };
1368 28537 : if (PREDICT_TRUE (is_tcp_udp[0]))
1369 : {
1370 6579 : udp_header_t *udp =
1371 6579 : (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1372 13158 : good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
1373 6579 : && udp->checksum == 0;
1374 : /* optimistically verify UDP length. */
1375 : u16 ip_len, udp_len;
1376 6579 : ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
1377 6579 : udp_len = clib_net_to_host_u16 (udp->length);
1378 6579 : len_diff[0] = ip_len - udp_len;
1379 : }
1380 28537 : if (PREDICT_TRUE (is_tcp_udp[1]))
1381 : {
1382 6579 : udp_header_t *udp =
1383 6579 : (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1384 13158 : good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1385 6579 : && udp->checksum == 0;
1386 : /* optimistically verify UDP length. */
1387 : u16 ip_len, udp_len;
1388 6579 : ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1389 6579 : udp_len = clib_net_to_host_u16 (udp->length);
1390 6579 : len_diff[1] = ip_len - udp_len;
1391 : }
1392 :
1393 28537 : good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1394 28537 : good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1395 :
1396 28537 : len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1397 28537 : len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1398 :
1399 : u8 need_csum[2];
1400 57074 : need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1401 19793 : && !good_l4_csum[0]
1402 48330 : && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1403 57074 : need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1404 19792 : && !good_l4_csum[1]
1405 48329 : && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1406 28537 : if (PREDICT_FALSE (need_csum[0]))
1407 : {
1408 19521 : flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1409 19521 : good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1410 19521 : error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1411 : }
1412 : else
1413 : {
1414 9016 : if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1415 0 : error[0] = IP6_ERROR_BAD_LENGTH;
1416 : }
1417 28537 : if (PREDICT_FALSE (need_csum[1]))
1418 : {
1419 19520 : flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1420 19520 : good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1421 19520 : error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1422 : }
1423 : else
1424 : {
1425 9017 : if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1426 0 : error[1] = IP6_ERROR_BAD_LENGTH;
1427 : }
1428 :
1429 :
1430 28537 : error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
1431 :
1432 28537 : error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
1433 :
1434 : STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1435 : IP6_ERROR_UDP_CHECKSUM,
1436 : "Wrong IP6 errors constants");
1437 : STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1438 : IP6_ERROR_ICMP_CHECKSUM,
1439 : "Wrong IP6 errors constants");
1440 :
1441 28537 : error[0] =
1442 28537 : !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1443 28537 : error[1] =
1444 28537 : !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
1445 :
1446 : /* Drop packets from unroutable hosts. */
1447 : /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1448 : u8 unroutable[2];
1449 57074 : unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1450 28513 : && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1451 57050 : && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
1452 57074 : unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1453 28513 : && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1454 57050 : && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
1455 28537 : if (PREDICT_FALSE (unroutable[0]))
1456 : {
1457 12561 : error[0] =
1458 12561 : !ip6_urpf_loose_check (im, b[0],
1459 : ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1460 12561 : : error[0];
1461 : }
1462 28537 : if (PREDICT_FALSE (unroutable[1]))
1463 : {
1464 12560 : error[1] =
1465 12560 : !ip6_urpf_loose_check (im, b[1],
1466 : ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1467 12560 : : error[1];
1468 : }
1469 :
1470 28537 : vnet_buffer (b[0])->ip.fib_index =
1471 28537 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1472 28537 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1473 28410 : vnet_buffer (b[0])->ip.fib_index;
1474 28537 : vnet_buffer (b[1])->ip.fib_index =
1475 28537 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1476 28537 : vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1477 28410 : vnet_buffer (b[1])->ip.fib_index;
1478 :
1479 28537 : vnet_buffer (b[0])->ip.rx_sw_if_index =
1480 28537 : vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1481 28537 : vnet_buffer (b[1])->ip.rx_sw_if_index =
1482 28537 : vnet_buffer (b[1])->sw_if_index[VLIB_RX];
1483 28537 : if (is_receive_dpo)
1484 : {
1485 : const receive_dpo_t *rd0, *rd1;
1486 : rd0 =
1487 28537 : receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1488 : rd1 =
1489 28537 : receive_dpo_get (vnet_buffer (b[1])->ip.adj_index[VLIB_TX]);
1490 28537 : if (rd0->rd_sw_if_index != ~0)
1491 28516 : vnet_buffer (b[0])->ip.rx_sw_if_index = rd0->rd_sw_if_index;
1492 28537 : if (rd1->rd_sw_if_index != ~0)
1493 28516 : vnet_buffer (b[1])->ip.rx_sw_if_index = rd1->rd_sw_if_index;
1494 : }
1495 : } /* head_of_feature_arc */
1496 :
1497 28537 : next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1498 28537 : next[0] =
1499 28537 : error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1500 28537 : next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1501 28537 : next[1] =
1502 28537 : error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
1503 :
1504 28537 : b[0]->error = error_node->errors[error[0]];
1505 28537 : b[1]->error = error_node->errors[error[1]];
1506 :
1507 28537 : if (head_of_feature_arc)
1508 : {
1509 : u8 ip6_unknown[2];
1510 28537 : ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1511 28537 : ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1512 28537 : if (PREDICT_TRUE (ip6_unknown[0]))
1513 : {
1514 28501 : u32 next32 = next[0];
1515 28501 : vnet_feature_arc_start (arc_index,
1516 28501 : vnet_buffer (b[0])->ip.rx_sw_if_index,
1517 : &next32, b[0]);
1518 28501 : next[0] = next32;
1519 : }
1520 28537 : if (PREDICT_TRUE (ip6_unknown[1]))
1521 : {
1522 28501 : u32 next32 = next[1];
1523 28501 : vnet_feature_arc_start (arc_index,
1524 28501 : vnet_buffer (b[1])->ip.rx_sw_if_index,
1525 28501 : &next32, b[1]);
1526 28501 : next[1] = next32;
1527 : }
1528 : }
1529 :
1530 : /* next */
1531 28537 : b += 2;
1532 28537 : next += 2;
1533 28537 : n_left_from -= 2;
1534 : }
1535 :
1536 6790 : while (n_left_from)
1537 : {
1538 : u8 error;
1539 3541 : error = IP6_ERROR_UNKNOWN_PROTOCOL;
1540 :
1541 : ip6_header_t *ip;
1542 3541 : ip = vlib_buffer_get_current (b[0]);
1543 :
1544 3541 : if (head_of_feature_arc)
1545 : {
1546 3541 : vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1547 3541 : u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
1548 :
1549 3541 : u32 flags = b[0]->flags;
1550 :
1551 3541 : vnet_buffer_oflags_t oflags = vnet_buffer (b[0])->oflags;
1552 :
1553 3558 : u32 l4_offload = (flags & VNET_BUFFER_F_OFFLOAD) &&
1554 17 : (oflags & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1555 : VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1556 :
1557 3541 : u32 good_l4_csum =
1558 3541 : (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload;
1559 : u32 udp_offset;
1560 3541 : i16 len_diff = 0;
1561 3541 : u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1562 3541 : if (PREDICT_TRUE (is_tcp_udp))
1563 : {
1564 365 : udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1565 : /* Don't verify UDP checksum for packets with explicit zero checksum. */
1566 365 : good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1567 365 : && udp->checksum == 0;
1568 : /* optimistically verify UDP length. */
1569 : u16 ip_len, udp_len;
1570 365 : ip_len = clib_net_to_host_u16 (ip->payload_length);
1571 365 : udp_len = clib_net_to_host_u16 (udp->length);
1572 365 : len_diff = ip_len - udp_len;
1573 : }
1574 :
1575 3541 : good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1576 3541 : len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1577 :
1578 3054 : u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN &&
1579 6595 : !good_l4_csum &&
1580 3036 : !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1581 3541 : if (PREDICT_FALSE (need_csum))
1582 : {
1583 3036 : flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1584 3036 : good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1585 3036 : error = IP6_ERROR_UNKNOWN_PROTOCOL;
1586 : }
1587 : else
1588 : {
1589 505 : if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1590 0 : error = IP6_ERROR_BAD_LENGTH;
1591 : }
1592 :
1593 :
1594 :
1595 3541 : error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
1596 : STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1597 : IP6_ERROR_UDP_CHECKSUM,
1598 : "Wrong IP6 errors constants");
1599 : STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1600 : IP6_ERROR_ICMP_CHECKSUM,
1601 : "Wrong IP6 errors constants");
1602 :
1603 3541 : error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1604 :
1605 : /* Drop packets from unroutable hosts. */
1606 : /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1607 3541 : u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1608 3539 : && type != IP_BUILTIN_PROTOCOL_ICMP
1609 7080 : && !ip6_address_is_link_local_unicast (&ip->src_address);
1610 3541 : if (PREDICT_FALSE (unroutable))
1611 : {
1612 565 : error =
1613 565 : !ip6_urpf_loose_check (im, b[0],
1614 : ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1615 : error;
1616 : }
1617 :
1618 3541 : vnet_buffer (b[0])->ip.fib_index =
1619 3541 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1620 3541 : vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1621 3446 : vnet_buffer (b[0])->ip.fib_index;
1622 :
1623 3541 : vnet_buffer (b[0])->ip.rx_sw_if_index =
1624 3541 : vnet_buffer (b[0])->sw_if_index[VLIB_RX];
1625 3541 : if (is_receive_dpo)
1626 : {
1627 : receive_dpo_t *rd;
1628 3541 : rd = receive_dpo_get (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
1629 3541 : if (rd->rd_sw_if_index != ~0)
1630 1300 : vnet_buffer (b[0])->ip.rx_sw_if_index = rd->rd_sw_if_index;
1631 : }
1632 : } /* head_of_feature_arc */
1633 :
1634 3541 : next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1635 3541 : next[0] =
1636 : error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1637 :
1638 3541 : b[0]->error = error_node->errors[error];
1639 :
1640 3541 : if (head_of_feature_arc)
1641 : {
1642 3541 : if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1643 : {
1644 3457 : u32 next32 = next[0];
1645 3457 : vnet_feature_arc_start (arc_index,
1646 3457 : vnet_buffer (b[0])->ip.rx_sw_if_index,
1647 : &next32, b[0]);
1648 3457 : next[0] = next32;
1649 : }
1650 : }
1651 :
1652 : /* next */
1653 3541 : b += 1;
1654 3541 : next += 1;
1655 3541 : n_left_from -= 1;
1656 : }
1657 :
1658 3249 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1659 3249 : return frame->n_vectors;
1660 : }
1661 :
1662 2300 : VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1663 : vlib_frame_t * frame)
1664 : {
1665 0 : return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */,
1666 : 0 /* ip6_local_inline */);
1667 : }
1668 :
1669 183788 : VLIB_REGISTER_NODE (ip6_local_node) =
1670 : {
1671 : .name = "ip6-local",
1672 : .vector_size = sizeof (u32),
1673 : .format_trace = format_ip6_forward_next_trace,
1674 : .n_errors = IP6_N_ERROR,
1675 : .error_counters = ip6_error_counters,
1676 : .n_next_nodes = IP_LOCAL_N_NEXT,
1677 : .next_nodes =
1678 : {
1679 : [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1680 : [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
1681 : [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1682 : [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1683 : [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-local-full-reassembly",
1684 : },
1685 : };
1686 :
1687 5549 : VLIB_NODE_FN (ip6_receive_local_node)
1688 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
1689 : {
1690 3249 : return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */,
1691 : 1 /* is_receive_dpo */);
1692 : }
1693 :
1694 183788 : VLIB_REGISTER_NODE (ip6_receive_local_node) = {
1695 : .name = "ip6-receive",
1696 : .vector_size = sizeof (u32),
1697 : .format_trace = format_ip6_forward_next_trace,
1698 : .sibling_of = "ip6-local"
1699 : };
1700 :
1701 2300 : VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
1702 : vlib_node_runtime_t * node,
1703 : vlib_frame_t * frame)
1704 : {
1705 0 : return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */,
1706 : 0 /* ip6_local_inline */);
1707 : }
1708 :
1709 183788 : VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
1710 : .name = "ip6-local-end-of-arc",
1711 : .vector_size = sizeof (u32),
1712 :
1713 : .format_trace = format_ip6_forward_next_trace,
1714 : .sibling_of = "ip6-local",
1715 : };
1716 :
1717 76635 : VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1718 : .arc_name = "ip6-local",
1719 : .node_name = "ip6-local-end-of-arc",
1720 : .runs_before = 0, /* not before any other features */
1721 : };
1722 :
1723 : #ifdef CLIB_MARCH_VARIANT
1724 : extern vlib_node_registration_t ip6_local_node;
1725 : #else
1726 : void
1727 1927 : ip6_register_protocol (u32 protocol, u32 node_index)
1728 : {
1729 1927 : vlib_main_t *vm = vlib_get_main ();
1730 1927 : ip6_main_t *im = &ip6_main;
1731 1927 : ip_lookup_main_t *lm = &im->lookup_main;
1732 :
1733 1927 : ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1734 1927 : lm->local_next_by_ip_protocol[protocol] =
1735 1927 : vlib_node_add_next (vm, ip6_local_node.index, node_index);
1736 1927 : }
1737 :
1738 : void
1739 62 : ip6_unregister_protocol (u32 protocol)
1740 : {
1741 62 : ip6_main_t *im = &ip6_main;
1742 62 : ip_lookup_main_t *lm = &im->lookup_main;
1743 :
1744 62 : ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1745 62 : lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1746 62 : }
1747 : #endif
1748 :
1749 : typedef enum
1750 : {
1751 : IP6_REWRITE_NEXT_DROP,
1752 : IP6_REWRITE_NEXT_ICMP_ERROR,
1753 : IP6_REWRITE_NEXT_FRAGMENT,
1754 : IP6_REWRITE_N_NEXT /* Last */
1755 : } ip6_rewrite_next_t;
1756 :
1757 : /**
1758 : * This bits of an IPv6 address to mask to construct a multicast
1759 : * MAC address
1760 : */
1761 : #define IP6_MCAST_ADDR_MASK 0xffffffff
1762 :
1763 : always_inline void
1764 9992210 : ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
1765 : u16 adj_packet_bytes, bool is_locally_generated,
1766 : u32 * next, u8 is_midchain, u32 * error)
1767 : {
1768 9992210 : if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1769 : {
1770 45 : if (is_locally_generated)
1771 : {
1772 : /* IP fragmentation */
1773 21 : ip_frag_set_vnet_buffer (b, adj_packet_bytes,
1774 : (is_midchain ?
1775 : IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1776 : IP_FRAG_NEXT_IP_REWRITE), 0);
1777 21 : *next = IP6_REWRITE_NEXT_FRAGMENT;
1778 21 : *error = IP6_ERROR_MTU_EXCEEDED;
1779 : }
1780 : else
1781 : {
1782 24 : *error = IP6_ERROR_MTU_EXCEEDED;
1783 24 : icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1784 : adj_packet_bytes);
1785 24 : *next = IP6_REWRITE_NEXT_ICMP_ERROR;
1786 : }
1787 : }
1788 9992210 : }
1789 :
1790 : always_inline uword
1791 231310 : ip6_rewrite_inline_with_gso (vlib_main_t * vm,
1792 : vlib_node_runtime_t * node,
1793 : vlib_frame_t * frame,
1794 : int do_counters, int is_midchain, int is_mcast)
1795 : {
1796 231310 : ip_lookup_main_t *lm = &ip6_main.lookup_main;
1797 231310 : u32 *from = vlib_frame_vector_args (frame);
1798 : u32 n_left_from, n_left_to_next, *to_next, next_index;
1799 : vlib_node_runtime_t *error_node =
1800 231310 : vlib_node_get_runtime (vm, ip6_input_node.index);
1801 :
1802 231310 : n_left_from = frame->n_vectors;
1803 231310 : next_index = node->cached_next_index;
1804 231310 : u32 thread_index = vm->thread_index;
1805 :
1806 462621 : while (n_left_from > 0)
1807 : {
1808 231311 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1809 :
1810 4971480 : while (n_left_from >= 4 && n_left_to_next >= 2)
1811 : {
1812 : const ip_adjacency_t *adj0, *adj1;
1813 : vlib_buffer_t *p0, *p1;
1814 : ip6_header_t *ip0, *ip1;
1815 : u32 pi0, rw_len0, next0, error0, adj_index0;
1816 : u32 pi1, rw_len1, next1, error1, adj_index1;
1817 : u32 tx_sw_if_index0, tx_sw_if_index1;
1818 : bool is_locally_originated0, is_locally_originated1;
1819 :
1820 : /* Prefetch next iteration. */
1821 : {
1822 : vlib_buffer_t *p2, *p3;
1823 :
1824 4740170 : p2 = vlib_get_buffer (vm, from[2]);
1825 4740170 : p3 = vlib_get_buffer (vm, from[3]);
1826 :
1827 4740170 : vlib_prefetch_buffer_header (p2, LOAD);
1828 4740170 : vlib_prefetch_buffer_header (p3, LOAD);
1829 :
1830 4740170 : clib_prefetch_store (p2->pre_data);
1831 4740170 : clib_prefetch_store (p3->pre_data);
1832 :
1833 4740170 : CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1834 4740170 : CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1835 : }
1836 :
1837 4740170 : pi0 = to_next[0] = from[0];
1838 4740170 : pi1 = to_next[1] = from[1];
1839 :
1840 4740170 : from += 2;
1841 4740170 : n_left_from -= 2;
1842 4740170 : to_next += 2;
1843 4740170 : n_left_to_next -= 2;
1844 :
1845 4740170 : p0 = vlib_get_buffer (vm, pi0);
1846 4740170 : p1 = vlib_get_buffer (vm, pi1);
1847 :
1848 4740170 : adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1849 4740170 : adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
1850 :
1851 4740170 : ip0 = vlib_buffer_get_current (p0);
1852 4740170 : ip1 = vlib_buffer_get_current (p1);
1853 :
1854 4740170 : error0 = error1 = IP6_ERROR_NONE;
1855 4740170 : next0 = next1 = IP6_REWRITE_NEXT_DROP;
1856 :
1857 4740170 : is_locally_originated0 =
1858 4740170 : p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1859 4740170 : if (PREDICT_TRUE (!is_locally_originated0))
1860 : {
1861 4702800 : i32 hop_limit0 = ip0->hop_limit;
1862 :
1863 : /* Input node should have reject packets with hop limit 0. */
1864 4702800 : ASSERT (ip0->hop_limit > 0);
1865 :
1866 4702800 : hop_limit0 -= 1;
1867 :
1868 4702800 : ip0->hop_limit = hop_limit0;
1869 :
1870 : /*
1871 : * If the hop count drops below 1 when forwarding, generate
1872 : * an ICMP response.
1873 : */
1874 4702800 : if (PREDICT_FALSE (hop_limit0 <= 0))
1875 : {
1876 286 : error0 = IP6_ERROR_TIME_EXPIRED;
1877 286 : next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1878 286 : vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1879 286 : icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1880 : ICMP6_time_exceeded_ttl_exceeded_in_transit,
1881 : 0);
1882 : }
1883 : }
1884 :
1885 4740170 : is_locally_originated1 =
1886 4740170 : p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1887 4740170 : if (PREDICT_TRUE (!is_locally_originated1))
1888 : {
1889 4702800 : i32 hop_limit1 = ip1->hop_limit;
1890 :
1891 : /* Input node should have reject packets with hop limit 0. */
1892 4702800 : ASSERT (ip1->hop_limit > 0);
1893 :
1894 4702800 : hop_limit1 -= 1;
1895 :
1896 4702800 : ip1->hop_limit = hop_limit1;
1897 :
1898 : /*
1899 : * If the hop count drops below 1 when forwarding, generate
1900 : * an ICMP response.
1901 : */
1902 4702800 : if (PREDICT_FALSE (hop_limit1 <= 0))
1903 : {
1904 286 : error1 = IP6_ERROR_TIME_EXPIRED;
1905 286 : next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1906 286 : vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1907 286 : icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1908 : ICMP6_time_exceeded_ttl_exceeded_in_transit,
1909 : 0);
1910 : }
1911 : }
1912 :
1913 4740170 : adj0 = adj_get (adj_index0);
1914 4740170 : adj1 = adj_get (adj_index1);
1915 :
1916 4740170 : rw_len0 = adj0[0].rewrite_header.data_bytes;
1917 4740170 : rw_len1 = adj1[0].rewrite_header.data_bytes;
1918 4740170 : vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1919 4740170 : vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
1920 :
1921 4740170 : if (do_counters)
1922 : {
1923 46 : vlib_increment_combined_counter
1924 : (&adjacency_counters,
1925 : thread_index, adj_index0, 1,
1926 46 : vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1927 46 : vlib_increment_combined_counter
1928 : (&adjacency_counters,
1929 : thread_index, adj_index1, 1,
1930 46 : vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1931 : }
1932 :
1933 : /* Check MTU of outgoing interface. */
1934 4740170 : u16 ip0_len =
1935 4740170 : clib_net_to_host_u16 (ip0->payload_length) +
1936 : sizeof (ip6_header_t);
1937 4740170 : u16 ip1_len =
1938 4740170 : clib_net_to_host_u16 (ip1->payload_length) +
1939 : sizeof (ip6_header_t);
1940 4740170 : if (p0->flags & VNET_BUFFER_F_GSO)
1941 47806 : ip0_len = gso_mtu_sz (p0);
1942 4740170 : if (p1->flags & VNET_BUFFER_F_GSO)
1943 53785 : ip1_len = gso_mtu_sz (p1);
1944 :
1945 4740170 : ip6_mtu_check (p0, ip0_len,
1946 4740170 : adj0[0].rewrite_header.max_l3_packet_bytes,
1947 : is_locally_originated0, &next0, is_midchain,
1948 : &error0);
1949 4740170 : ip6_mtu_check (p1, ip1_len,
1950 4740170 : adj1[0].rewrite_header.max_l3_packet_bytes,
1951 : is_locally_originated1, &next1, is_midchain,
1952 : &error1);
1953 : /* Don't adjust the buffer for hop count issue; icmp-error node
1954 : * wants to see the IP header */
1955 4740170 : if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1956 : {
1957 4739880 : p0->current_data -= rw_len0;
1958 4739880 : p0->current_length += rw_len0;
1959 4739880 : tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1960 4739880 : vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1961 4739880 : next0 = adj0[0].rewrite_header.next_index;
1962 4739880 : if (PREDICT_FALSE
1963 : (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1964 2321930 : vnet_feature_arc_start_w_cfg_index
1965 2321930 : (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
1966 : adj0->ia_cfg_index);
1967 : }
1968 : else
1969 : {
1970 294 : p0->error = error_node->errors[error0];
1971 : }
1972 4740170 : if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1973 : {
1974 4739880 : p1->current_data -= rw_len1;
1975 4739880 : p1->current_length += rw_len1;
1976 :
1977 4739880 : tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1978 4739880 : vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1979 4739880 : next1 = adj1[0].rewrite_header.next_index;
1980 :
1981 4739880 : if (PREDICT_FALSE
1982 : (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1983 2329800 : vnet_feature_arc_start_w_cfg_index
1984 2329800 : (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1,
1985 : adj1->ia_cfg_index);
1986 : }
1987 : else
1988 : {
1989 294 : p1->error = error_node->errors[error1];
1990 : }
1991 :
1992 4740170 : if (is_midchain)
1993 : {
1994 : /* before we paint on the next header, update the L4
1995 : * checksums if required, since there's no offload on a tunnel */
1996 7110 : vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
1997 : 1 /* is_ip6 */ );
1998 7110 : vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
1999 : 1 /* is_ip6 */ );
2000 :
2001 : /* Guess we are only writing on ipv6 header. */
2002 7110 : vnet_rewrite_two_headers (adj0[0], adj1[0],
2003 : ip0, ip1, sizeof (ip6_header_t));
2004 : }
2005 : else
2006 : /* Guess we are only writing on simple Ethernet header. */
2007 4733060 : vnet_rewrite_two_headers (adj0[0], adj1[0],
2008 : ip0, ip1, sizeof (ethernet_header_t));
2009 :
2010 4740170 : if (is_midchain)
2011 : {
2012 7110 : if (adj0->sub_type.midchain.fixup_func)
2013 6166 : adj0->sub_type.midchain.fixup_func
2014 : (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2015 7110 : if (adj1->sub_type.midchain.fixup_func)
2016 6166 : adj1->sub_type.midchain.fixup_func
2017 : (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
2018 : }
2019 4740170 : if (is_mcast)
2020 : {
2021 : /*
2022 : * copy bytes from the IP address into the MAC rewrite
2023 : */
2024 664 : vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2025 : adj0->
2026 664 : rewrite_header.dst_mcast_offset,
2027 : &ip0->dst_address.as_u32[3],
2028 : (u8 *) ip0);
2029 664 : vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2030 : adj1->
2031 664 : rewrite_header.dst_mcast_offset,
2032 : &ip1->dst_address.as_u32[3],
2033 : (u8 *) ip1);
2034 : }
2035 :
2036 4740170 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2037 : to_next, n_left_to_next,
2038 : pi0, pi1, next0, next1);
2039 : }
2040 :
2041 743169 : while (n_left_from > 0 && n_left_to_next > 0)
2042 : {
2043 : ip_adjacency_t *adj0;
2044 : vlib_buffer_t *p0;
2045 : ip6_header_t *ip0;
2046 : u32 pi0, rw_len0;
2047 : u32 adj_index0, next0, error0;
2048 : u32 tx_sw_if_index0;
2049 : bool is_locally_originated0;
2050 :
2051 511858 : pi0 = to_next[0] = from[0];
2052 :
2053 511858 : p0 = vlib_get_buffer (vm, pi0);
2054 :
2055 511858 : adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2056 :
2057 511858 : adj0 = adj_get (adj_index0);
2058 :
2059 511858 : ip0 = vlib_buffer_get_current (p0);
2060 :
2061 511858 : error0 = IP6_ERROR_NONE;
2062 511858 : next0 = IP6_REWRITE_NEXT_DROP;
2063 :
2064 : /* Check hop limit */
2065 511858 : is_locally_originated0 =
2066 511858 : p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
2067 511858 : if (PREDICT_TRUE (!is_locally_originated0))
2068 : {
2069 506116 : i32 hop_limit0 = ip0->hop_limit;
2070 :
2071 506116 : ASSERT (ip0->hop_limit > 0);
2072 :
2073 506116 : hop_limit0 -= 1;
2074 :
2075 506116 : ip0->hop_limit = hop_limit0;
2076 :
2077 506116 : if (PREDICT_FALSE (hop_limit0 <= 0))
2078 : {
2079 : /*
2080 : * If the hop count drops below 1 when forwarding, generate
2081 : * an ICMP response.
2082 : */
2083 9 : error0 = IP6_ERROR_TIME_EXPIRED;
2084 9 : next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2085 9 : vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2086 9 : icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2087 : ICMP6_time_exceeded_ttl_exceeded_in_transit,
2088 : 0);
2089 : }
2090 : }
2091 :
2092 511858 : if (is_midchain)
2093 : {
2094 429 : vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
2095 : 1 /* is_ip6 */ );
2096 :
2097 : /* Guess we are only writing on ip6 header. */
2098 429 : vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t));
2099 : }
2100 : else
2101 : /* Guess we are only writing on simple Ethernet header. */
2102 511429 : vnet_rewrite_one_header (adj0[0], ip0,
2103 : sizeof (ethernet_header_t));
2104 :
2105 : /* Update packet buffer attributes/set output interface. */
2106 511858 : rw_len0 = adj0[0].rewrite_header.data_bytes;
2107 511858 : vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2108 :
2109 511858 : if (do_counters)
2110 : {
2111 11 : vlib_increment_combined_counter
2112 : (&adjacency_counters,
2113 : thread_index, adj_index0, 1,
2114 11 : vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2115 : }
2116 :
2117 : /* Check MTU of outgoing interface. */
2118 511858 : u16 ip0_len =
2119 511858 : clib_net_to_host_u16 (ip0->payload_length) +
2120 : sizeof (ip6_header_t);
2121 511858 : if (p0->flags & VNET_BUFFER_F_GSO)
2122 74946 : ip0_len = gso_mtu_sz (p0);
2123 :
2124 511858 : ip6_mtu_check (p0, ip0_len,
2125 511858 : adj0[0].rewrite_header.max_l3_packet_bytes,
2126 : is_locally_originated0, &next0, is_midchain,
2127 : &error0);
2128 : /* Don't adjust the buffer for hop count issue; icmp-error node
2129 : * wants to see the IP header */
2130 511858 : if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2131 : {
2132 511820 : p0->current_data -= rw_len0;
2133 511820 : p0->current_length += rw_len0;
2134 :
2135 511820 : tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2136 :
2137 511820 : vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2138 511820 : next0 = adj0[0].rewrite_header.next_index;
2139 :
2140 511820 : if (PREDICT_FALSE
2141 : (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2142 347875 : vnet_feature_arc_start_w_cfg_index
2143 347875 : (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
2144 : adj0->ia_cfg_index);
2145 : }
2146 : else
2147 : {
2148 38 : p0->error = error_node->errors[error0];
2149 : }
2150 :
2151 511858 : if (is_midchain)
2152 : {
2153 429 : if (adj0->sub_type.midchain.fixup_func)
2154 368 : adj0->sub_type.midchain.fixup_func
2155 : (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2156 : }
2157 511858 : if (is_mcast)
2158 : {
2159 1966 : vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2160 : adj0->
2161 1966 : rewrite_header.dst_mcast_offset,
2162 : &ip0->dst_address.as_u32[3],
2163 : (u8 *) ip0);
2164 : }
2165 :
2166 511858 : from += 1;
2167 511858 : n_left_from -= 1;
2168 511858 : to_next += 1;
2169 511858 : n_left_to_next -= 1;
2170 :
2171 511858 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2172 : to_next, n_left_to_next,
2173 : pi0, next0);
2174 : }
2175 :
2176 231311 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2177 : }
2178 :
2179 : /* Need to do trace after rewrites to pick up new packet data. */
2180 231310 : if (node->flags & VLIB_NODE_FLAG_TRACE)
2181 2997 : ip6_forward_next_trace (vm, node, frame, VLIB_TX);
2182 :
2183 231310 : return frame->n_vectors;
2184 : }
2185 :
2186 : always_inline uword
2187 231310 : ip6_rewrite_inline (vlib_main_t * vm,
2188 : vlib_node_runtime_t * node,
2189 : vlib_frame_t * frame,
2190 : int do_counters, int is_midchain, int is_mcast)
2191 : {
2192 231310 : return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2193 : is_midchain, is_mcast);
2194 : }
2195 :
2196 231443 : VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
2197 : vlib_node_runtime_t * node,
2198 : vlib_frame_t * frame)
2199 : {
2200 229143 : if (adj_are_counters_enabled ())
2201 3 : return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2202 : else
2203 229140 : return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2204 : }
2205 :
2206 2300 : VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
2207 : vlib_node_runtime_t * node,
2208 : vlib_frame_t * frame)
2209 : {
2210 0 : if (adj_are_counters_enabled ())
2211 0 : return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2212 : else
2213 0 : return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2214 : }
2215 :
2216 4253 : VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
2217 : vlib_node_runtime_t * node,
2218 : vlib_frame_t * frame)
2219 : {
2220 1953 : if (adj_are_counters_enabled ())
2221 4 : return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2222 : else
2223 1949 : return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
2224 : }
2225 :
2226 2514 : VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
2227 : vlib_node_runtime_t * node,
2228 : vlib_frame_t * frame)
2229 : {
2230 214 : if (adj_are_counters_enabled ())
2231 0 : return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2232 : else
2233 214 : return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
2234 : }
2235 :
2236 2300 : VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
2237 : vlib_node_runtime_t * node,
2238 : vlib_frame_t * frame)
2239 : {
2240 0 : if (adj_are_counters_enabled ())
2241 0 : return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2242 : else
2243 0 : return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
2244 : }
2245 :
2246 : /* *INDENT-OFF* */
2247 183788 : VLIB_REGISTER_NODE (ip6_midchain_node) = {
2248 : .name = "ip6-midchain",
2249 : .vector_size = sizeof (u32),
2250 : .format_trace = format_ip6_forward_next_trace,
2251 : .sibling_of = "ip6-rewrite",
2252 : };
2253 :
2254 183788 : VLIB_REGISTER_NODE (ip6_rewrite_node) =
2255 : {
2256 : .name = "ip6-rewrite",
2257 : .vector_size = sizeof (u32),
2258 : .format_trace = format_ip6_rewrite_trace,
2259 : .n_errors = IP6_N_ERROR,
2260 : .error_counters = ip6_error_counters,
2261 : .n_next_nodes = IP6_REWRITE_N_NEXT,
2262 : .next_nodes =
2263 : {
2264 : [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
2265 : [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
2266 : [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
2267 : },
2268 : };
2269 :
2270 183788 : VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
2271 : .name = "ip6-rewrite-bcast",
2272 : .vector_size = sizeof (u32),
2273 :
2274 : .format_trace = format_ip6_rewrite_trace,
2275 : .sibling_of = "ip6-rewrite",
2276 : };
2277 :
2278 183788 : VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2279 : {
2280 : .name = "ip6-rewrite-mcast",
2281 : .vector_size = sizeof (u32),
2282 : .format_trace = format_ip6_rewrite_trace,
2283 : .sibling_of = "ip6-rewrite",
2284 : };
2285 :
2286 :
2287 183788 : VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
2288 : {
2289 : .name = "ip6-mcast-midchain",
2290 : .vector_size = sizeof (u32),
2291 : .format_trace = format_ip6_rewrite_trace,
2292 : .sibling_of = "ip6-rewrite",
2293 : };
2294 :
2295 : /* *INDENT-ON* */
2296 :
2297 : /*
2298 : * Hop-by-Hop handling
2299 : */
2300 : #ifndef CLIB_MARCH_VARIANT
2301 : ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2302 : #endif /* CLIB_MARCH_VARIANT */
2303 :
2304 : #define foreach_ip6_hop_by_hop_error \
2305 : _(PROCESSED, "pkts with ip6 hop-by-hop options") \
2306 : _(FORMAT, "incorrectly formatted hop-by-hop options") \
2307 : _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2308 :
2309 : /* *INDENT-OFF* */
2310 : typedef enum
2311 : {
2312 : #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2313 : foreach_ip6_hop_by_hop_error
2314 : #undef _
2315 : IP6_HOP_BY_HOP_N_ERROR,
2316 : } ip6_hop_by_hop_error_t;
2317 : /* *INDENT-ON* */
2318 :
2319 : /*
2320 : * Primary h-b-h handler trace support
2321 : * We work pretty hard on the problem for obvious reasons
2322 : */
2323 : typedef struct
2324 : {
2325 : u32 next_index;
2326 : u32 trace_len;
2327 : u8 option_data[256];
2328 : } ip6_hop_by_hop_trace_t;
2329 :
2330 : extern vlib_node_registration_t ip6_hop_by_hop_node;
2331 :
2332 : static char *ip6_hop_by_hop_error_strings[] = {
2333 : #define _(sym,string) string,
2334 : foreach_ip6_hop_by_hop_error
2335 : #undef _
2336 : };
2337 :
2338 : #ifndef CLIB_MARCH_VARIANT
2339 : u8 *
2340 0 : format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2341 : {
2342 0 : ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2343 0 : int total_len = va_arg (*args, int);
2344 : ip6_hop_by_hop_option_t *opt0, *limit0;
2345 0 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2346 : u8 type0;
2347 0 : s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2348 0 : hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2349 :
2350 0 : opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2351 0 : limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2352 :
2353 0 : while (opt0 < limit0)
2354 : {
2355 0 : type0 = opt0->type;
2356 0 : switch (type0)
2357 : {
2358 0 : case 0: /* Pad, just stop */
2359 0 : opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2360 0 : break;
2361 :
2362 0 : default:
2363 0 : if (hm->trace[type0])
2364 : {
2365 0 : s = (*hm->trace[type0]) (s, opt0);
2366 : }
2367 : else
2368 : {
2369 0 : s = format (s, "\n unrecognized option %d length %d", type0,
2370 0 : opt0->length);
2371 : }
2372 0 : opt0 =
2373 0 : (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2374 : sizeof (ip6_hop_by_hop_option_t));
2375 0 : break;
2376 : }
2377 : }
2378 0 : return s;
2379 : }
2380 : #endif
2381 :
2382 : static u8 *
2383 3 : format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2384 : {
2385 3 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2386 3 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2387 3 : ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
2388 : ip6_hop_by_hop_header_t *hbh0;
2389 : ip6_hop_by_hop_option_t *opt0, *limit0;
2390 3 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2391 :
2392 : u8 type0;
2393 :
2394 3 : hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
2395 :
2396 3 : s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
2397 3 : t->next_index, (hbh0->length + 1) << 3, t->trace_len);
2398 :
2399 3 : opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2400 3 : limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
2401 :
2402 18 : while (opt0 < limit0)
2403 : {
2404 15 : type0 = opt0->type;
2405 15 : switch (type0)
2406 : {
2407 12 : case 0: /* Pad, just stop */
2408 12 : opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2409 12 : break;
2410 :
2411 3 : default:
2412 3 : if (hm->trace[type0])
2413 : {
2414 0 : s = (*hm->trace[type0]) (s, opt0);
2415 : }
2416 : else
2417 : {
2418 3 : s = format (s, "\n unrecognized option %d length %d", type0,
2419 3 : opt0->length);
2420 : }
2421 3 : opt0 =
2422 3 : (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2423 : sizeof (ip6_hop_by_hop_option_t));
2424 3 : break;
2425 : }
2426 : }
2427 3 : return s;
2428 : }
2429 :
2430 : always_inline u8
2431 2 : ip6_scan_hbh_options (vlib_buffer_t * b0,
2432 : ip6_header_t * ip0,
2433 : ip6_hop_by_hop_header_t * hbh0,
2434 : ip6_hop_by_hop_option_t * opt0,
2435 : ip6_hop_by_hop_option_t * limit0, u32 * next0)
2436 : {
2437 2 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2438 : u8 type0;
2439 2 : u8 error0 = 0;
2440 :
2441 4 : while (opt0 < limit0)
2442 : {
2443 2 : type0 = opt0->type;
2444 2 : switch (type0)
2445 : {
2446 0 : case 0: /* Pad1 */
2447 0 : opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2448 0 : continue;
2449 2 : case 1: /* PadN */
2450 2 : break;
2451 0 : default:
2452 0 : if (hm->options[type0])
2453 : {
2454 0 : if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2455 : {
2456 0 : error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2457 0 : return (error0);
2458 : }
2459 : }
2460 : else
2461 : {
2462 : /* Unrecognized mandatory option, check the two high order bits */
2463 0 : switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2464 : {
2465 0 : case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2466 0 : break;
2467 0 : case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2468 0 : error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2469 0 : *next0 = IP_LOOKUP_NEXT_DROP;
2470 0 : break;
2471 0 : case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2472 0 : error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2473 0 : *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2474 0 : icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2475 : ICMP6_parameter_problem_unrecognized_option,
2476 0 : (u8 *) opt0 - (u8 *) ip0);
2477 0 : break;
2478 0 : case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2479 0 : error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2480 0 : if (!ip6_address_is_multicast (&ip0->dst_address))
2481 : {
2482 0 : *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2483 0 : icmp6_error_set_vnet_buffer (b0,
2484 : ICMP6_parameter_problem,
2485 : ICMP6_parameter_problem_unrecognized_option,
2486 0 : (u8 *) opt0 - (u8 *) ip0);
2487 : }
2488 : else
2489 : {
2490 0 : *next0 = IP_LOOKUP_NEXT_DROP;
2491 : }
2492 0 : break;
2493 : }
2494 0 : return (error0);
2495 : }
2496 : }
2497 2 : opt0 =
2498 2 : (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2499 : sizeof (ip6_hop_by_hop_option_t));
2500 : }
2501 2 : return (error0);
2502 : }
2503 :
2504 : /*
2505 : * Process the Hop-by-Hop Options header
2506 : */
2507 2302 : VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
2508 : vlib_node_runtime_t * node,
2509 : vlib_frame_t * frame)
2510 : {
2511 : vlib_node_runtime_t *error_node =
2512 2 : vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
2513 2 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2514 : u32 n_left_from, *from, *to_next;
2515 : ip_lookup_next_t next_index;
2516 :
2517 2 : from = vlib_frame_vector_args (frame);
2518 2 : n_left_from = frame->n_vectors;
2519 2 : next_index = node->cached_next_index;
2520 :
2521 4 : while (n_left_from > 0)
2522 : {
2523 : u32 n_left_to_next;
2524 :
2525 2 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2526 :
2527 2 : while (n_left_from >= 4 && n_left_to_next >= 2)
2528 : {
2529 : u32 bi0, bi1;
2530 : vlib_buffer_t *b0, *b1;
2531 : u32 next0, next1;
2532 : ip6_header_t *ip0, *ip1;
2533 : ip6_hop_by_hop_header_t *hbh0, *hbh1;
2534 : ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2535 0 : u8 error0 = 0, error1 = 0;
2536 :
2537 : /* Prefetch next iteration. */
2538 : {
2539 : vlib_buffer_t *p2, *p3;
2540 :
2541 0 : p2 = vlib_get_buffer (vm, from[2]);
2542 0 : p3 = vlib_get_buffer (vm, from[3]);
2543 :
2544 0 : vlib_prefetch_buffer_header (p2, LOAD);
2545 0 : vlib_prefetch_buffer_header (p3, LOAD);
2546 :
2547 0 : CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2548 0 : CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2549 : }
2550 :
2551 : /* Speculatively enqueue b0, b1 to the current next frame */
2552 0 : to_next[0] = bi0 = from[0];
2553 0 : to_next[1] = bi1 = from[1];
2554 0 : from += 2;
2555 0 : to_next += 2;
2556 0 : n_left_from -= 2;
2557 0 : n_left_to_next -= 2;
2558 :
2559 0 : b0 = vlib_get_buffer (vm, bi0);
2560 0 : b1 = vlib_get_buffer (vm, bi1);
2561 :
2562 : /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2563 0 : u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2564 0 : ip_adjacency_t *adj0 = adj_get (adj_index0);
2565 0 : u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2566 0 : ip_adjacency_t *adj1 = adj_get (adj_index1);
2567 :
2568 : /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2569 0 : next0 = adj0->lookup_next_index;
2570 0 : next1 = adj1->lookup_next_index;
2571 :
2572 0 : ip0 = vlib_buffer_get_current (b0);
2573 0 : ip1 = vlib_buffer_get_current (b1);
2574 0 : hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2575 0 : hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2576 0 : opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2577 0 : opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2578 0 : limit0 =
2579 : (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2580 0 : ((hbh0->length + 1) << 3));
2581 0 : limit1 =
2582 : (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2583 0 : ((hbh1->length + 1) << 3));
2584 :
2585 : /*
2586 : * Basic validity checks
2587 : */
2588 0 : if ((hbh0->length + 1) << 3 >
2589 0 : clib_net_to_host_u16 (ip0->payload_length))
2590 : {
2591 0 : error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2592 0 : next0 = IP_LOOKUP_NEXT_DROP;
2593 0 : goto outdual;
2594 : }
2595 : /* Scan the set of h-b-h options, process ones that we understand */
2596 0 : error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2597 :
2598 0 : if ((hbh1->length + 1) << 3 >
2599 0 : clib_net_to_host_u16 (ip1->payload_length))
2600 : {
2601 0 : error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2602 0 : next1 = IP_LOOKUP_NEXT_DROP;
2603 0 : goto outdual;
2604 : }
2605 : /* Scan the set of h-b-h options, process ones that we understand */
2606 0 : error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2607 :
2608 0 : outdual:
2609 : /* Has the classifier flagged this buffer for special treatment? */
2610 0 : if (PREDICT_FALSE
2611 : ((error0 == 0)
2612 : && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2613 0 : next0 = hm->next_override;
2614 :
2615 : /* Has the classifier flagged this buffer for special treatment? */
2616 0 : if (PREDICT_FALSE
2617 : ((error1 == 0)
2618 : && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2619 0 : next1 = hm->next_override;
2620 :
2621 0 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2622 : {
2623 0 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
2624 : {
2625 : ip6_hop_by_hop_trace_t *t =
2626 0 : vlib_add_trace (vm, node, b0, sizeof (*t));
2627 0 : u32 trace_len = (hbh0->length + 1) << 3;
2628 0 : t->next_index = next0;
2629 : /* Capture the h-b-h option verbatim */
2630 0 : trace_len =
2631 : trace_len <
2632 : ARRAY_LEN (t->option_data) ? trace_len :
2633 : ARRAY_LEN (t->option_data);
2634 0 : t->trace_len = trace_len;
2635 0 : clib_memcpy_fast (t->option_data, hbh0, trace_len);
2636 : }
2637 0 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
2638 : {
2639 : ip6_hop_by_hop_trace_t *t =
2640 0 : vlib_add_trace (vm, node, b1, sizeof (*t));
2641 0 : u32 trace_len = (hbh1->length + 1) << 3;
2642 0 : t->next_index = next1;
2643 : /* Capture the h-b-h option verbatim */
2644 0 : trace_len =
2645 : trace_len <
2646 : ARRAY_LEN (t->option_data) ? trace_len :
2647 : ARRAY_LEN (t->option_data);
2648 0 : t->trace_len = trace_len;
2649 0 : clib_memcpy_fast (t->option_data, hbh1, trace_len);
2650 : }
2651 :
2652 : }
2653 :
2654 0 : b0->error = error_node->errors[error0];
2655 0 : b1->error = error_node->errors[error1];
2656 :
2657 : /* verify speculative enqueue, maybe switch current next frame */
2658 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2659 : n_left_to_next, bi0, bi1, next0,
2660 : next1);
2661 : }
2662 :
2663 4 : while (n_left_from > 0 && n_left_to_next > 0)
2664 : {
2665 : u32 bi0;
2666 : vlib_buffer_t *b0;
2667 : u32 next0;
2668 : ip6_header_t *ip0;
2669 : ip6_hop_by_hop_header_t *hbh0;
2670 : ip6_hop_by_hop_option_t *opt0, *limit0;
2671 2 : u8 error0 = 0;
2672 :
2673 : /* Speculatively enqueue b0 to the current next frame */
2674 2 : bi0 = from[0];
2675 2 : to_next[0] = bi0;
2676 2 : from += 1;
2677 2 : to_next += 1;
2678 2 : n_left_from -= 1;
2679 2 : n_left_to_next -= 1;
2680 :
2681 2 : b0 = vlib_get_buffer (vm, bi0);
2682 : /*
2683 : * Default use the next_index from the adjacency.
2684 : * A HBH option rarely redirects to a different node
2685 : */
2686 2 : u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2687 2 : ip_adjacency_t *adj0 = adj_get (adj_index0);
2688 2 : next0 = adj0->lookup_next_index;
2689 :
2690 2 : ip0 = vlib_buffer_get_current (b0);
2691 2 : hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2692 2 : opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2693 2 : limit0 =
2694 : (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2695 2 : ((hbh0->length + 1) << 3));
2696 :
2697 : /*
2698 : * Basic validity checks
2699 : */
2700 4 : if ((hbh0->length + 1) << 3 >
2701 2 : clib_net_to_host_u16 (ip0->payload_length))
2702 : {
2703 0 : error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2704 0 : next0 = IP_LOOKUP_NEXT_DROP;
2705 0 : goto out0;
2706 : }
2707 :
2708 : /* Scan the set of h-b-h options, process ones that we understand */
2709 2 : error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2710 :
2711 2 : out0:
2712 : /* Has the classifier flagged this buffer for special treatment? */
2713 2 : if (PREDICT_FALSE
2714 : ((error0 == 0)
2715 : && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2716 0 : next0 = hm->next_override;
2717 :
2718 2 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2719 : {
2720 : ip6_hop_by_hop_trace_t *t =
2721 2 : vlib_add_trace (vm, node, b0, sizeof (*t));
2722 2 : u32 trace_len = (hbh0->length + 1) << 3;
2723 2 : t->next_index = next0;
2724 : /* Capture the h-b-h option verbatim */
2725 2 : trace_len =
2726 : trace_len <
2727 : ARRAY_LEN (t->option_data) ? trace_len :
2728 : ARRAY_LEN (t->option_data);
2729 2 : t->trace_len = trace_len;
2730 2 : clib_memcpy_fast (t->option_data, hbh0, trace_len);
2731 : }
2732 :
2733 2 : b0->error = error_node->errors[error0];
2734 :
2735 : /* verify speculative enqueue, maybe switch current next frame */
2736 2 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2737 : n_left_to_next, bi0, next0);
2738 : }
2739 2 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2740 : }
2741 2 : return frame->n_vectors;
2742 : }
2743 :
2744 : /* *INDENT-OFF* */
2745 183788 : VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2746 : {
2747 : .name = "ip6-hop-by-hop",
2748 : .sibling_of = "ip6-lookup",
2749 : .vector_size = sizeof (u32),
2750 : .format_trace = format_ip6_hop_by_hop_trace,
2751 : .type = VLIB_NODE_TYPE_INTERNAL,
2752 : .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
2753 : .error_strings = ip6_hop_by_hop_error_strings,
2754 : .n_next_nodes = 0,
2755 : };
2756 : /* *INDENT-ON* */
2757 :
2758 : static clib_error_t *
2759 575 : ip6_hop_by_hop_init (vlib_main_t * vm)
2760 : {
2761 575 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2762 575 : clib_memset (hm->options, 0, sizeof (hm->options));
2763 575 : clib_memset (hm->trace, 0, sizeof (hm->trace));
2764 575 : hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
2765 575 : return (0);
2766 : }
2767 :
2768 15551 : VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2769 :
2770 : #ifndef CLIB_MARCH_VARIANT
2771 : void
2772 0 : ip6_hbh_set_next_override (uword next)
2773 : {
2774 0 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2775 :
2776 0 : hm->next_override = next;
2777 0 : }
2778 :
2779 : int
2780 1150 : ip6_hbh_register_option (u8 option,
2781 : int options (vlib_buffer_t * b, ip6_header_t * ip,
2782 : ip6_hop_by_hop_option_t * opt),
2783 : u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
2784 : {
2785 1150 : ip6_main_t *im = &ip6_main;
2786 1150 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2787 :
2788 : ASSERT ((u32) option < ARRAY_LEN (hm->options));
2789 :
2790 : /* Already registered */
2791 1150 : if (hm->options[option])
2792 0 : return (-1);
2793 :
2794 1150 : hm->options[option] = options;
2795 1150 : hm->trace[option] = trace;
2796 :
2797 : /* Set global variable */
2798 1150 : im->hbh_enabled = 1;
2799 :
2800 1150 : return (0);
2801 : }
2802 :
2803 : int
2804 0 : ip6_hbh_unregister_option (u8 option)
2805 : {
2806 0 : ip6_main_t *im = &ip6_main;
2807 0 : ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2808 :
2809 : ASSERT ((u32) option < ARRAY_LEN (hm->options));
2810 :
2811 : /* Not registered */
2812 0 : if (!hm->options[option])
2813 0 : return (-1);
2814 :
2815 0 : hm->options[option] = NULL;
2816 0 : hm->trace[option] = NULL;
2817 :
2818 : /* Disable global knob if this was the last option configured */
2819 : int i;
2820 0 : bool found = false;
2821 0 : for (i = 0; i < 256; i++)
2822 : {
2823 0 : if (hm->options[option])
2824 : {
2825 0 : found = true;
2826 0 : break;
2827 : }
2828 : }
2829 0 : if (!found)
2830 0 : im->hbh_enabled = 0;
2831 :
2832 0 : return (0);
2833 : }
2834 :
2835 : /* Global IP6 main. */
2836 : ip6_main_t ip6_main;
2837 : #endif
2838 :
2839 : static clib_error_t *
2840 575 : ip6_lookup_init (vlib_main_t * vm)
2841 : {
2842 575 : ip6_main_t *im = &ip6_main;
2843 : clib_error_t *error;
2844 : uword i;
2845 :
2846 575 : if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2847 0 : return error;
2848 :
2849 74750 : for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2850 : {
2851 : u32 j, i0, i1;
2852 :
2853 74175 : i0 = i / 32;
2854 74175 : i1 = i % 32;
2855 :
2856 186875 : for (j = 0; j < i0; j++)
2857 112700 : im->fib_masks[i].as_u32[j] = ~0;
2858 :
2859 74175 : if (i1)
2860 71300 : im->fib_masks[i].as_u32[i0] =
2861 71300 : clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
2862 : }
2863 :
2864 575 : ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2865 :
2866 : /* Create FIB with index 0 and table id of 0. */
2867 575 : fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2868 : FIB_SOURCE_DEFAULT_ROUTE);
2869 575 : mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2870 : MFIB_SOURCE_DEFAULT_ROUTE);
2871 :
2872 : {
2873 : pg_node_t *pn;
2874 575 : pn = pg_get_node (ip6_lookup_node.index);
2875 575 : pn->unformat_edit = unformat_pg_ip6_header;
2876 : }
2877 :
2878 : /* Unless explicitly configured, don't process HBH options */
2879 575 : im->hbh_enabled = 0;
2880 :
2881 575 : return error;
2882 : }
2883 :
2884 13247 : VLIB_INIT_FUNCTION (ip6_lookup_init);
2885 :
2886 : static clib_error_t *
2887 0 : set_ip6_flow_hash_command_fn (vlib_main_t * vm,
2888 : unformat_input_t * input,
2889 : vlib_cli_command_t * cmd)
2890 : {
2891 0 : int matched = 0;
2892 0 : u32 table_id = 0;
2893 0 : u32 flow_hash_config = 0;
2894 : int rv;
2895 :
2896 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2897 : {
2898 0 : if (unformat (input, "table %d", &table_id))
2899 0 : matched = 1;
2900 : #define _(a, b, v) \
2901 : else if (unformat (input, #a)) \
2902 : { \
2903 : flow_hash_config |= v; \
2904 : matched = 1; \
2905 : }
2906 0 : foreach_flow_hash_bit
2907 : #undef _
2908 : else
2909 0 : break;
2910 : }
2911 :
2912 0 : if (matched == 0)
2913 0 : return clib_error_return (0, "unknown input `%U'",
2914 : format_unformat_error, input);
2915 :
2916 0 : rv = ip_flow_hash_set (AF_IP6, table_id, flow_hash_config);
2917 0 : switch (rv)
2918 : {
2919 0 : case 0:
2920 0 : break;
2921 :
2922 0 : case -1:
2923 0 : return clib_error_return (0, "no such FIB table %d", table_id);
2924 :
2925 0 : default:
2926 0 : clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2927 0 : break;
2928 : }
2929 :
2930 0 : return 0;
2931 : }
2932 :
2933 : /*?
2934 : * Configure the set of IPv6 fields used by the flow hash.
2935 : *
2936 : * @cliexpar
2937 : * @parblock
2938 : * Example of how to set the flow hash on a given table:
2939 : * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2940 : *
2941 : * Example of display the configured flow hash:
2942 : * @cliexstart{show ip6 fib}
2943 : * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2944 : * @::/0
2945 : * unicast-ip6-chain
2946 : * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2947 : * [0] [@0]: dpo-drop ip6
2948 : * fe80::/10
2949 : * unicast-ip6-chain
2950 : * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2951 : * [0] [@2]: dpo-receive
2952 : * ff02::1/128
2953 : * unicast-ip6-chain
2954 : * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2955 : * [0] [@2]: dpo-receive
2956 : * ff02::2/128
2957 : * unicast-ip6-chain
2958 : * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2959 : * [0] [@2]: dpo-receive
2960 : * ff02::16/128
2961 : * unicast-ip6-chain
2962 : * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2963 : * [0] [@2]: dpo-receive
2964 : * ff02::1:ff00:0/104
2965 : * unicast-ip6-chain
2966 : * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2967 : * [0] [@2]: dpo-receive
2968 : * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2969 : * @::/0
2970 : * unicast-ip6-chain
2971 : * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2972 : * [0] [@0]: dpo-drop ip6
2973 : * @::a:1:1:0:4/126
2974 : * unicast-ip6-chain
2975 : * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2976 : * [0] [@4]: ipv6-glean: af_packet0
2977 : * @::a:1:1:0:7/128
2978 : * unicast-ip6-chain
2979 : * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2980 : * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2981 : * fe80::/10
2982 : * unicast-ip6-chain
2983 : * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2984 : * [0] [@2]: dpo-receive
2985 : * fe80::fe:3eff:fe3e:9222/128
2986 : * unicast-ip6-chain
2987 : * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2988 : * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2989 : * ff02::1/128
2990 : * unicast-ip6-chain
2991 : * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2992 : * [0] [@2]: dpo-receive
2993 : * ff02::2/128
2994 : * unicast-ip6-chain
2995 : * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2996 : * [0] [@2]: dpo-receive
2997 : * ff02::16/128
2998 : * unicast-ip6-chain
2999 : * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3000 : * [0] [@2]: dpo-receive
3001 : * ff02::1:ff00:0/104
3002 : * unicast-ip6-chain
3003 : * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3004 : * [0] [@2]: dpo-receive
3005 : * @cliexend
3006 : * @endparblock
3007 : ?*/
3008 : /* *INDENT-OFF* */
3009 285289 : VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = {
3010 : .path = "set ip6 flow-hash",
3011 : .short_help = "set ip6 flow-hash table <table-id> [src] [dst] [sport] "
3012 : "[dport] [proto] [reverse] [flowlabel]",
3013 : .function = set_ip6_flow_hash_command_fn,
3014 : };
3015 : /* *INDENT-ON* */
3016 :
3017 : static clib_error_t *
3018 0 : show_ip6_local_command_fn (vlib_main_t * vm,
3019 : unformat_input_t * input, vlib_cli_command_t * cmd)
3020 : {
3021 0 : ip6_main_t *im = &ip6_main;
3022 0 : ip_lookup_main_t *lm = &im->lookup_main;
3023 : int i;
3024 :
3025 0 : vlib_cli_output (vm, "Protocols handled by ip6_local");
3026 0 : for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
3027 : {
3028 0 : if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
3029 : {
3030 :
3031 0 : u32 node_index = vlib_get_node (vm,
3032 0 : ip6_local_node.index)->
3033 0 : next_nodes[lm->local_next_by_ip_protocol[i]];
3034 0 : vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3035 : node_index);
3036 : }
3037 : }
3038 0 : return 0;
3039 : }
3040 :
3041 :
3042 :
3043 : /*?
3044 : * Display the set of protocols handled by the local IPv6 stack.
3045 : *
3046 : * @cliexpar
3047 : * Example of how to display local protocol table:
3048 : * @cliexstart{show ip6 local}
3049 : * Protocols handled by ip6_local
3050 : * 17
3051 : * 43
3052 : * 58
3053 : * 115
3054 : * @cliexend
3055 : ?*/
3056 : /* *INDENT-OFF* */
3057 285289 : VLIB_CLI_COMMAND (show_ip6_local, static) =
3058 : {
3059 : .path = "show ip6 local",
3060 : .function = show_ip6_local_command_fn,
3061 : .short_help = "show ip6 local",
3062 : };
3063 : /* *INDENT-ON* */
3064 :
3065 : #ifndef CLIB_MARCH_VARIANT
3066 : int
3067 0 : vnet_set_ip6_classify_intfc (vlib_main_t *vm, u32 sw_if_index, u32 table_index)
3068 : {
3069 0 : vnet_main_t *vnm = vnet_get_main ();
3070 0 : vnet_interface_main_t *im = &vnm->interface_main;
3071 0 : ip6_main_t *ipm = &ip6_main;
3072 0 : ip_lookup_main_t *lm = &ipm->lookup_main;
3073 0 : vnet_classify_main_t *cm = &vnet_classify_main;
3074 : ip6_address_t *if_addr;
3075 :
3076 0 : if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3077 0 : return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3078 :
3079 0 : if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3080 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
3081 :
3082 0 : vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3083 0 : lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
3084 :
3085 0 : if_addr = ip6_interface_first_address (ipm, sw_if_index);
3086 :
3087 0 : if (NULL != if_addr)
3088 : {
3089 0 : fib_prefix_t pfx = {
3090 : .fp_len = 128,
3091 : .fp_proto = FIB_PROTOCOL_IP6,
3092 : .fp_addr.ip6 = *if_addr,
3093 : };
3094 : u32 fib_index;
3095 :
3096 0 : fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3097 : sw_if_index);
3098 0 : if (table_index != (u32) ~ 0)
3099 : {
3100 0 : dpo_id_t dpo = DPO_INVALID;
3101 0 : dpo_set (&dpo,
3102 : DPO_CLASSIFY,
3103 : DPO_PROTO_IP6,
3104 : classify_dpo_create (DPO_PROTO_IP6, table_index));
3105 0 : fib_table_entry_special_dpo_add (fib_index,
3106 : &pfx,
3107 : FIB_SOURCE_CLASSIFY,
3108 : FIB_ENTRY_FLAG_NONE, &dpo);
3109 0 : dpo_reset (&dpo);
3110 : }
3111 : else
3112 : {
3113 0 : fib_table_entry_special_remove (fib_index,
3114 : &pfx, FIB_SOURCE_CLASSIFY);
3115 : }
3116 : }
3117 :
3118 0 : return 0;
3119 : }
3120 : #endif
3121 :
3122 : static clib_error_t *
3123 0 : set_ip6_classify_command_fn (vlib_main_t * vm,
3124 : unformat_input_t * input,
3125 : vlib_cli_command_t * cmd)
3126 : {
3127 0 : u32 table_index = ~0;
3128 0 : int table_index_set = 0;
3129 0 : u32 sw_if_index = ~0;
3130 : int rv;
3131 :
3132 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3133 : {
3134 0 : if (unformat (input, "table-index %d", &table_index))
3135 0 : table_index_set = 1;
3136 0 : else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3137 : vnet_get_main (), &sw_if_index))
3138 : ;
3139 : else
3140 0 : break;
3141 : }
3142 :
3143 0 : if (table_index_set == 0)
3144 0 : return clib_error_return (0, "classify table-index must be specified");
3145 :
3146 0 : if (sw_if_index == ~0)
3147 0 : return clib_error_return (0, "interface / subif must be specified");
3148 :
3149 0 : rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3150 :
3151 0 : switch (rv)
3152 : {
3153 0 : case 0:
3154 0 : break;
3155 :
3156 0 : case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3157 0 : return clib_error_return (0, "No such interface");
3158 :
3159 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
3160 0 : return clib_error_return (0, "No such classifier table");
3161 : }
3162 0 : return 0;
3163 : }
3164 :
3165 : /*?
3166 : * Assign a classification table to an interface. The classification
3167 : * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3168 : * commands. Once the table is create, use this command to filter packets
3169 : * on an interface.
3170 : *
3171 : * @cliexpar
3172 : * Example of how to assign a classification table to an interface:
3173 : * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3174 : ?*/
3175 : /* *INDENT-OFF* */
3176 285289 : VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3177 : {
3178 : .path = "set ip6 classify",
3179 : .short_help =
3180 : "set ip6 classify intfc <interface> table-index <classify-idx>",
3181 : .function = set_ip6_classify_command_fn,
3182 : };
3183 : /* *INDENT-ON* */
3184 :
3185 : /*
3186 : * fd.io coding-style-patch-verification: ON
3187 : *
3188 : * Local Variables:
3189 : * eval: (c-set-style "gnu")
3190 : * End:
3191 : */
|