blob: d9c015f6fb41fdcf85dd94e6977d182a28e01a28 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
AkshayaNadahallied4a2fd2016-08-09 13:38:04 +05302 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * 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>
Ole Troan313f7e22018-04-10 16:02:51 +020042#include <vnet/ip/ip_frag.h>
Neale Rannscbe25aa2019-09-30 10:53:31 +000043#include <vnet/ip/ip6_link.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050044#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053047#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010048#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000049#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070050#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010051#include <vnet/dpo/classify_dpo.h>
Neale Rannsba4a5bf2020-01-09 06:43:14 +000052#include <vnet/classify/vnet_classify.h>
Neale Ranns68d48d92021-06-03 14:59:47 +000053#include <vnet/pg/pg.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
Damjan Marion38173502019-02-13 19:30:09 +010055#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -070056#include <vppinfra/bihash_template.c>
Damjan Marion38173502019-02-13 19:30:09 +010057#endif
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080058#include <vnet/ip/ip6_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000059#include <vnet/interface_output.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070060
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053061/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
62#define OI_DECAP 0x80000000
63
Ed Warnickecb9cada2015-12-08 15:45:58 -070064static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -050065ip6_add_interface_prefix_routes (ip6_main_t * im,
66 u32 sw_if_index,
67 u32 fib_index,
68 ip6_address_t * address, u32 address_length)
69{
70 ip_lookup_main_t *lm = &im->lookup_main;
71 ip_interface_prefix_t *if_prefix;
72
Neale Ranns1ff3c152019-10-07 22:40:54 -070073 /* *INDENT-OFF* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -050074 ip_interface_prefix_key_t key = {
75 .prefix = {
Neale Ranns1ff3c152019-10-07 22:40:54 -070076 .fp_len = address_length,
77 .fp_proto = FIB_PROTOCOL_IP6,
78 .fp_addr.ip6 = {
79 .as_u64 = {
80 address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
81 address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
82 },
83 },
84 },
Matthew Smith6c92f5b2019-08-07 11:46:30 -050085 .sw_if_index = sw_if_index,
86 };
Neale Ranns1ff3c152019-10-07 22:40:54 -070087 /* *INDENT-ON* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -050088
89 /* If prefix already set on interface, just increment ref count & return */
90 if_prefix = ip_get_interface_prefix (lm, &key);
91 if (if_prefix)
92 {
93 if_prefix->ref_count += 1;
94 return;
95 }
96
97 /* New prefix - allocate a pool entry, initialize it, add to the hash */
98 pool_get (lm->if_prefix_pool, if_prefix);
99 if_prefix->ref_count = 1;
100 clib_memcpy (&if_prefix->key, &key, sizeof (key));
101 mhash_set (&lm->prefix_to_if_prefix_index, &key,
102 if_prefix - lm->if_prefix_pool, 0 /* old value */ );
103
104 /* length < 128 - add glean */
105 if (address_length < 128)
106 {
107 /* set the glean route for the prefix */
108 fib_table_entry_update_one_path (fib_index, &key.prefix,
109 FIB_SOURCE_INTERFACE,
110 (FIB_ENTRY_FLAG_CONNECTED |
111 FIB_ENTRY_FLAG_ATTACHED),
112 DPO_PROTO_IP6,
113 /* No next-hop address */
114 NULL, sw_if_index,
115 /* invalid FIB index */
116 ~0, 1,
117 /* no out-label stack */
118 NULL, FIB_ROUTE_PATH_FLAG_NONE);
119 }
120}
121
122static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
124 ip6_main_t * im, u32 fib_index,
125 ip_interface_address_t * a)
126{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 ip_lookup_main_t *lm = &im->lookup_main;
128 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100129 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130 .fp_len = a->address_length,
131 .fp_proto = FIB_PROTOCOL_IP6,
132 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500135 /* set special routes for the prefix if needed */
136 ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
137 address, a->address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100139 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100142 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500143 lm->classify_table_index_by_sw_if_index[sw_if_index];
144 if (classify_table_index != (u32) ~ 0)
145 {
146 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100147
Dave Barachd7cb1b52016-12-09 09:52:16 -0500148 dpo_set (&dpo,
149 DPO_CLASSIFY,
150 DPO_PROTO_IP6,
151 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100152
Dave Barachd7cb1b52016-12-09 09:52:16 -0500153 fib_table_entry_special_dpo_add (fib_index,
154 &pfx,
155 FIB_SOURCE_CLASSIFY,
156 FIB_ENTRY_FLAG_NONE, &dpo);
157 dpo_reset (&dpo);
158 }
159 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100160
Neale Rannsf12a83f2017-04-18 09:09:40 -0700161 fib_table_entry_update_one_path (fib_index, &pfx,
162 FIB_SOURCE_INTERFACE,
163 (FIB_ENTRY_FLAG_CONNECTED |
164 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700165 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700166 &pfx.fp_addr,
167 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169}
170
171static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500172ip6_del_interface_prefix_routes (ip6_main_t * im,
173 u32 sw_if_index,
174 u32 fib_index,
175 ip6_address_t * address, u32 address_length)
176{
177 ip_lookup_main_t *lm = &im->lookup_main;
178 ip_interface_prefix_t *if_prefix;
179
Neale Ranns1ff3c152019-10-07 22:40:54 -0700180 /* *INDENT-OFF* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500181 ip_interface_prefix_key_t key = {
182 .prefix = {
Neale Ranns1ff3c152019-10-07 22:40:54 -0700183 .fp_len = address_length,
184 .fp_proto = FIB_PROTOCOL_IP6,
185 .fp_addr.ip6 = {
186 .as_u64 = {
187 address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
188 address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
189 },
190 },
191 },
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500192 .sw_if_index = sw_if_index,
193 };
Neale Ranns1ff3c152019-10-07 22:40:54 -0700194 /* *INDENT-ON* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500195
196 if_prefix = ip_get_interface_prefix (lm, &key);
197 if (!if_prefix)
198 {
199 clib_warning ("Prefix not found while deleting %U",
200 format_ip4_address_and_length, address, address_length);
201 return;
202 }
203
204 /* If not deleting last intf addr in prefix, decrement ref count & return */
205 if_prefix->ref_count -= 1;
206 if (if_prefix->ref_count > 0)
207 return;
208
Neale Ranns1ff3c152019-10-07 22:40:54 -0700209 /* length <= 128, delete glean route */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500210 if (address_length <= 128)
211 {
212 /* remove glean route for prefix */
213 fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500214 }
215
216 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
217 pool_put (lm->if_prefix_pool, if_prefix);
218}
219
220static void
221ip6_del_interface_routes (u32 sw_if_index, ip6_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100222 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500223 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500225 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500226 .fp_len = 128,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500227 .fp_proto = FIB_PROTOCOL_IP6,
228 .fp_addr.ip6 = *address,
229 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500231 /* delete special routes for the prefix if needed */
232 ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
233 address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100234
Dave Barachd7cb1b52016-12-09 09:52:16 -0500235 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236}
237
Damjan Marion38173502019-02-13 19:30:09 +0100238#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500240ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100241{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500242 ip6_main_t *im = &ip6_main;
John Lo4a302ee2020-05-12 22:34:39 -0400243 vnet_main_t *vnm = vnet_get_main ();
244 vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100246 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 /*
249 * enable/disable only on the 1<->0 transition
250 */
251 if (is_enable)
252 {
253 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500254 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100255 }
256 else
257 {
Neale Ranns75152282017-01-09 01:00:45 -0800258 /* The ref count is 0 when an address is removed from an interface that has
259 * no address - this is not a ciritical error */
260 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
261 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500262 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263 }
264
Neale Ranns8269d3d2018-01-30 09:02:20 -0800265 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Neale Ranns630198f2017-05-22 09:20:20 -0400266 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100267
Neale Ranns8269d3d2018-01-30 09:02:20 -0800268 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
269 sw_if_index, !is_enable, 0, 0);
John Lo4a302ee2020-05-12 22:34:39 -0400270
271 if (is_enable)
272 hi->l3_if_count++;
273 else if (hi->l3_if_count)
274 hi->l3_if_count--;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100275}
276
Neale Rannsdf089a82016-10-02 16:39:06 +0100277/* get first interface address */
278ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800279ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100280{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 ip_lookup_main_t *lm = &im->lookup_main;
282 ip_interface_address_t *ia = 0;
283 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100284
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100286 foreach_ip_interface_address (lm, ia, sw_if_index,
287 1 /* honor unnumbered */,
288 ({
289 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
290 result = a;
291 break;
292 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100294 return result;
295}
296
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297clib_error_t *
298ip6_add_del_interface_address (vlib_main_t * vm,
299 u32 sw_if_index,
300 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500303 vnet_main_t *vnm = vnet_get_main ();
304 ip6_main_t *im = &ip6_main;
305 ip_lookup_main_t *lm = &im->lookup_main;
Neale Ranns59f71132020-04-08 12:19:38 +0000306 clib_error_t *error = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500308 ip6_address_fib_t ip6_af, *addr_fib = 0;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000309 const ip6_address_t *ll_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310
Pim van Pelt76b19ce2021-08-10 23:44:44 +0200311 error = vnet_sw_interface_supports_addressing (vnm, sw_if_index);
312 if (error)
Matthew Smith1b6c7932021-09-24 15:27:36 -0500313 {
314 vnm->api_errno = VNET_API_ERROR_UNSUPPORTED;
315 return error;
316 }
Pavel Kotucek57808982017-08-02 08:20:19 +0200317
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200318 if (ip6_address_is_link_local_unicast (address))
319 {
320 if (address_length != 128)
321 {
322 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
323 return
324 clib_error_create
325 ("prefix length of link-local address must be 128");
326 }
327 if (!is_del)
328 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000329 int rv;
330
Neale Rannsec40a7d2020-04-23 07:36:12 +0000331 rv = ip6_link_set_local_address (sw_if_index, address);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000332
333 if (rv)
334 {
335 vnm->api_errno = rv;
336 return clib_error_create ("address not assignable");
337 }
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200338 }
339 else
340 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000341 ll_addr = ip6_get_link_local_address (sw_if_index);
342 if (ip6_address_is_equal (ll_addr, address))
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200343 {
344 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
345 return clib_error_create ("address not deletable");
346 }
347 else
348 {
349 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
350 return clib_error_create ("address not found");
351 }
352 }
Neale Rannsec40a7d2020-04-23 07:36:12 +0000353
354 return (NULL);
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200355 }
356
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 ip6_addr_fib_init (&ip6_af, address,
358 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
359 vec_add1 (addr_fib, ip6_af);
360
Neale Ranns744902e2017-08-14 10:35:44 -0700361 /* *INDENT-OFF* */
362 if (!is_del)
363 {
364 /* When adding an address check that it does not conflict
365 with an existing address on any interface in this table. */
366 ip_interface_address_t *ia;
367 vnet_sw_interface_t *sif;
368
Damjan Marionb2c31b62020-12-13 21:47:40 +0100369 pool_foreach (sif, vnm->interface_main.sw_interfaces)
370 {
Neale Ranns744902e2017-08-14 10:35:44 -0700371 if (im->fib_index_by_sw_if_index[sw_if_index] ==
372 im->fib_index_by_sw_if_index[sif->sw_if_index])
373 {
374 foreach_ip_interface_address
375 (&im->lookup_main, ia, sif->sw_if_index,
376 0 /* honor unnumbered */ ,
377 ({
378 ip6_address_t * x =
379 ip_interface_address_get_address
380 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000381
Neale Ranns744902e2017-08-14 10:35:44 -0700382 if (ip6_destination_matches_route
383 (im, address, x, ia->address_length) ||
384 ip6_destination_matches_route (im,
385 x,
386 address,
387 address_length))
388 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500389 /* an intf may have >1 addr from the same prefix */
390 if ((sw_if_index == sif->sw_if_index) &&
391 (ia->address_length == address_length) &&
392 !ip6_address_is_equal (x, address))
393 continue;
394
Neale Ranns59f71132020-04-08 12:19:38 +0000395 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
396 /* if the address we're comparing against is stale
397 * then the CP has not added this one back yet, maybe
398 * it never will, so we have to assume it won't and
399 * ignore it. if it does add it back, then it will fail
400 * because this one is now present */
401 continue;
402
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500403 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700404 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
Neale Ranns59f71132020-04-08 12:19:38 +0000405 error = clib_error_create
Neale Ranns744902e2017-08-14 10:35:44 -0700406 ("failed to add %U which conflicts with %U for interface %U",
407 format_ip6_address_and_length, address,
408 address_length,
409 format_ip6_address_and_length, x,
410 ia->address_length,
411 format_vnet_sw_if_index_name, vnm,
412 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000413 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700414 }
415 }));
416 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100417 }
Neale Ranns744902e2017-08-14 10:35:44 -0700418 }
419 /* *INDENT-ON* */
420
Neale Ranns59f71132020-04-08 12:19:38 +0000421 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422
Neale Ranns59f71132020-04-08 12:19:38 +0000423 if (is_del)
424 {
425 if (~0 == if_address_index)
426 {
427 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
428 error = clib_error_create ("%U not found for interface %U",
429 lm->format_address_and_length,
430 addr_fib, address_length,
431 format_vnet_sw_if_index_name, vnm,
432 sw_if_index);
433 goto done;
434 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
yedgdbd366b2020-05-14 10:51:53 +0800436 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
437 address_length, sw_if_index);
438 if (error)
439 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000440 }
441 else
442 {
443 if (~0 != if_address_index)
444 {
445 ip_interface_address_t *ia;
446
447 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
448
449 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
450 {
451 if (ia->sw_if_index == sw_if_index)
452 {
453 /* re-adding an address during the replace action.
454 * consdier this the update. clear the flag and
455 * we're done */
456 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
457 goto done;
458 }
459 else
460 {
461 /* The prefix is moving from one interface to another.
462 * delete the stale and add the new */
463 ip6_add_del_interface_address (vm,
464 ia->sw_if_index,
465 address, address_length, 1);
466 ia = NULL;
467 error = ip_interface_address_add (lm, sw_if_index,
468 addr_fib, address_length,
469 &if_address_index);
470 }
471 }
472 else
473 {
474 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
475 error = clib_error_create
476 ("Prefix %U already found on interface %U",
477 lm->format_address_and_length, addr_fib, address_length,
478 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
479 }
480 }
481 else
482 error = ip_interface_address_add (lm, sw_if_index,
483 addr_fib, address_length,
484 &if_address_index);
485 }
486
487 if (error)
488 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000491 if (!is_del)
Neale Rannsec40a7d2020-04-23 07:36:12 +0000492 ip6_link_enable (sw_if_index, NULL);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000493
Neale Ranns1ff3c152019-10-07 22:40:54 -0700494 /* intf addr routes are added/deleted on admin up/down */
495 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
496 {
497 if (is_del)
498 ip6_del_interface_routes (sw_if_index,
499 im, ip6_af.fib_index, address,
500 address_length);
501 else
502 ip6_add_interface_routes (vnm, sw_if_index,
503 im, ip6_af.fib_index,
504 pool_elt_at_index (lm->if_address_pool,
505 if_address_index));
506 }
Neale Ranns59f71132020-04-08 12:19:38 +0000507
508 ip6_add_del_interface_address_callback_t *cb;
509 vec_foreach (cb, im->add_del_interface_address_callbacks)
510 cb->function (im, cb->function_opaque, sw_if_index,
511 address, address_length, if_address_index, is_del);
512
Neale Rannscbe25aa2019-09-30 10:53:31 +0000513 if (is_del)
514 ip6_link_disable (sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
Dave Barachd7cb1b52016-12-09 09:52:16 -0500516done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517 vec_free (addr_fib);
518 return error;
519}
520
Damjan Marion38173502019-02-13 19:30:09 +0100521#endif
522
523static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500524ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500526 ip6_main_t *im = &ip6_main;
527 ip_interface_address_t *ia;
528 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 u32 is_admin_up, fib_index;
530
Dave Barachd7cb1b52016-12-09 09:52:16 -0500531 vec_validate_init_empty (im->
532 lookup_main.if_address_pool_index_by_sw_if_index,
533 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534
535 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
536
537 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
538
Dave Barachd7cb1b52016-12-09 09:52:16 -0500539 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400540 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700541 0 /* honor unnumbered */,
542 ({
543 a = ip_interface_address_get_address (&im->lookup_main, ia);
544 if (is_admin_up)
545 ip6_add_interface_routes (vnm, sw_if_index,
546 im, fib_index,
547 ia);
548 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500549 ip6_del_interface_routes (sw_if_index, im, fib_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550 a, ia->address_length);
551 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500552 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553
554 return 0;
555}
556
557VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
558
Dave Barachd6534602016-06-14 18:38:02 -0400559/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500560/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100561VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
562{
563 .arc_name = "ip6-unicast",
564 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500565 .last_in_arc = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100566 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
567};
568
Dave Barachd7cb1b52016-12-09 09:52:16 -0500569VNET_FEATURE_INIT (ip6_flow_classify, static) =
570{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100571 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700572 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100573 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700574};
575
Dave Barachd7cb1b52016-12-09 09:52:16 -0500576VNET_FEATURE_INIT (ip6_inacl, static) =
577{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100578 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400579 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100580 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400581};
582
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583VNET_FEATURE_INIT (ip6_policer_classify, static) =
584{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100585 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700586 .node_name = "ip6-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100587 .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700588};
589
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590VNET_FEATURE_INIT (ip6_ipsec, static) =
591{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100592 .arc_name = "ip6-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100593 .node_name = "ipsec6-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100594 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400595};
596
Dave Barachd7cb1b52016-12-09 09:52:16 -0500597VNET_FEATURE_INIT (ip6_l2tp, static) =
598{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100599 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400600 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100601 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400602};
603
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604VNET_FEATURE_INIT (ip6_vpath, static) =
605{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100606 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400607 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500608 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
609};
610
611VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
612{
613 .arc_name = "ip6-unicast",
614 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100615 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400616};
617
Neale Ranns8269d3d2018-01-30 09:02:20 -0800618VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500619{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100620 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800621 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400622 .runs_before = VNET_FEATURES ("ip6-lookup"),
623};
624
625VNET_FEATURE_INIT (ip6_lookup, static) =
626{
627 .arc_name = "ip6-unicast",
628 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100629 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100630};
631
Dave Barachd6534602016-06-14 18:38:02 -0400632/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100633VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
634{
635 .arc_name = "ip6-multicast",
636 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500637 .last_in_arc = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100638 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
639};
640
641VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
642 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400643 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000644 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400645};
646
Neale Ranns8269d3d2018-01-30 09:02:20 -0800647VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100648 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800649 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400650 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
651};
652
653VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
654 .arc_name = "ip6-multicast",
655 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100657};
Dave Barach5331c722016-08-17 11:54:30 -0400658
659/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100660VNET_FEATURE_ARC_INIT (ip6_output, static) =
661{
662 .arc_name = "ip6-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800663 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500664 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100665 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400666};
667
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100668VNET_FEATURE_INIT (ip6_outacl, static) = {
669 .arc_name = "ip6-output",
670 .node_name = "ip6-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100671 .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100672};
673
Matus Fabian08a6f012016-11-15 06:08:51 -0800674VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
675 .arc_name = "ip6-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100676 .node_name = "ipsec6-output-feature",
Matus Fabian08a6f012016-11-15 06:08:51 -0800677 .runs_before = VNET_FEATURES ("interface-output"),
678};
679
Damjan Marion8b3191e2016-11-09 19:54:20 +0100680VNET_FEATURE_INIT (ip6_interface_output, static) = {
681 .arc_name = "ip6-output",
682 .node_name = "interface-output",
683 .runs_before = 0, /* not before any other features */
684};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500685/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400686
Damjan Marion38173502019-02-13 19:30:09 +0100687static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500688ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700690 ip6_main_t *im = &ip6_main;
691
Nathan Skrzypczak7854b462021-08-16 16:13:40 +0200692 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
693 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Florin Corasb5c13fd2017-05-10 12:32:53 -0700694
Nathan Skrzypczak7854b462021-08-16 16:13:40 +0200695 if (is_add)
696 {
697 /* Fill in lookup tables with default table (0). */
698 im->fib_index_by_sw_if_index[sw_if_index] = 0;
699 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
700 }
701 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200702 {
703 /* Ensure that IPv6 is disabled */
704 ip6_main_t *im6 = &ip6_main;
705 ip_lookup_main_t *lm6 = &im6->lookup_main;
706 ip_interface_address_t *ia = 0;
707 ip6_address_t *address;
708 vlib_main_t *vm = vlib_get_main ();
709
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700710 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200711 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700712 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200713 ({
714 address = ip_interface_address_get_address (lm6, ia);
715 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
716 }));
717 /* *INDENT-ON* */
718 ip6_mfib_interface_enable_disable (sw_if_index, 0);
719 }
720
Neale Ranns8269d3d2018-01-30 09:02:20 -0800721 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723
Neale Ranns8269d3d2018-01-30 09:02:20 -0800724 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
725 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 return /* no error */ 0;
728}
729
730VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
731
Damjan Marion38173502019-02-13 19:30:09 +0100732VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
733 vlib_node_runtime_t * node,
734 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200735{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100736 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200737}
738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100740
Dave Barachd7cb1b52016-12-09 09:52:16 -0500741/* *INDENT-OFF* */
742VLIB_REGISTER_NODE (ip6_lookup_node) =
743{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 .name = "ip6-lookup",
745 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100746 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200747 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200748 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700749};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751
Damjan Marion38173502019-02-13 19:30:09 +0100752VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
753 vlib_node_runtime_t * node,
754 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200755{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400757 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200758 u32 thread_index = vm->thread_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500759 ip6_main_t *im = &ip6_main;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400760 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
761 u16 nexts[VLIB_FRAME_SIZE], *next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100762
763 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400764 n_left = frame->n_vectors;
765 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100766
Neale Ranns3ce72b22019-05-27 08:21:32 -0400767 vlib_get_buffers (vm, from, bufs, n_left);
768
769 while (n_left >= 4)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100770 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400771 const load_balance_t *lb0, *lb1;
772 const ip6_header_t *ip0, *ip1;
773 u32 lbi0, hc0, lbi1, hc1;
774 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100775
Neale Ranns3ce72b22019-05-27 08:21:32 -0400776 /* Prefetch next iteration. */
777 {
778 vlib_prefetch_buffer_header (b[2], STORE);
779 vlib_prefetch_buffer_header (b[3], STORE);
Dave Barach75fc8542016-10-11 16:16:02 -0400780
Neale Ranns3ce72b22019-05-27 08:21:32 -0400781 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
782 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
783 }
784
785 ip0 = vlib_buffer_get_current (b[0]);
786 ip1 = vlib_buffer_get_current (b[1]);
787 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
788 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
789
790 lb0 = load_balance_get (lbi0);
791 lb1 = load_balance_get (lbi1);
792
793 /*
794 * this node is for via FIBs we can re-use the hash value from the
795 * to node if present.
796 * We don't want to use the same hash value at each level in the recursion
797 * graph as that would lead to polarisation
798 */
799 hc0 = hc1 = 0;
800
801 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400803 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500804 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400805 hc0 = vnet_buffer (b[0])->ip.flow_hash =
806 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700807 }
808 else
809 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400810 hc0 = vnet_buffer (b[0])->ip.flow_hash =
811 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400813 dpo0 = load_balance_get_fwd_bucket
814 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
815 }
816 else
817 {
818 dpo0 = load_balance_get_bucket_i (lb0, 0);
819 }
820 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
821 {
822 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400824 hc1 = vnet_buffer (b[1])->ip.flow_hash =
825 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700827 else
828 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400829 hc1 = vnet_buffer (b[1])->ip.flow_hash =
830 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700831 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400832 dpo1 = load_balance_get_fwd_bucket
833 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
834 }
835 else
836 {
837 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500838 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000839
Neale Ranns3ce72b22019-05-27 08:21:32 -0400840 next[0] = dpo0->dpoi_next_node;
841 next[1] = dpo1->dpoi_next_node;
842
843 /* Only process the HBH Option Header if explicitly configured to do so */
844 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400846 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
847 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
848 }
849 /* Only process the HBH Option Header if explicitly configured to do so */
850 if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
851 {
852 next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
853 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500854 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100855
Neale Ranns3ce72b22019-05-27 08:21:32 -0400856 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
857 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
858
859 vlib_increment_combined_counter
860 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
861 vlib_increment_combined_counter
862 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
863
864 b += 2;
865 next += 2;
866 n_left -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100867 }
868
Neale Ranns3ce72b22019-05-27 08:21:32 -0400869 while (n_left > 0)
870 {
871 const load_balance_t *lb0;
872 const ip6_header_t *ip0;
873 const dpo_id_t *dpo0;
874 u32 lbi0, hc0;
875
876 ip0 = vlib_buffer_get_current (b[0]);
877 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
878
879 lb0 = load_balance_get (lbi0);
880
881 hc0 = 0;
882 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
883 {
884 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
885 {
886 hc0 = vnet_buffer (b[0])->ip.flow_hash =
887 vnet_buffer (b[0])->ip.flow_hash >> 1;
888 }
889 else
890 {
891 hc0 = vnet_buffer (b[0])->ip.flow_hash =
892 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
893 }
894 dpo0 = load_balance_get_fwd_bucket
895 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
896 }
897 else
898 {
899 dpo0 = load_balance_get_bucket_i (lb0, 0);
900 }
901
902 next[0] = dpo0->dpoi_next_node;
903 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
904
905 /* Only process the HBH Option Header if explicitly configured to do so */
906 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
907 {
908 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
909 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
910 }
911
912 vlib_increment_combined_counter
913 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
914
915 b += 1;
916 next += 1;
917 n_left -= 1;
918 }
919
920 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
921
Neale Rannsa71844f2018-11-08 07:31:36 -0800922 if (node->flags & VLIB_NODE_FLAG_TRACE)
923 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
924
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100925 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200926}
927
Dave Barachd7cb1b52016-12-09 09:52:16 -0500928/* *INDENT-OFF* */
929VLIB_REGISTER_NODE (ip6_load_balance_node) =
930{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100931 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200932 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200933 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100934 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200935};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500936/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200937
Dave Barachd7cb1b52016-12-09 09:52:16 -0500938typedef struct
939{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 /* Adjacency taken. */
941 u32 adj_index;
942 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500943 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944
945 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946 u8 packet_data[128 - 1 * sizeof (u32)];
947}
948ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
Damjan Marion38173502019-02-13 19:30:09 +0100950#ifndef CLIB_MARCH_VARIANT
John Lo2b81eb82017-01-30 13:12:10 -0500951u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100954 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
955 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200957 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100958
Neale Rannsdc617b82020-08-20 08:22:56 +0000959 s = format (s, "%Ufib:%d adj:%d flow:%d",
960 format_white_space, indent,
961 t->fib_index, t->adj_index, t->flow_hash);
962 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500963 format_white_space, indent,
964 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100965 return s;
966}
Damjan Marion38173502019-02-13 19:30:09 +0100967#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100968
Dave Barachd7cb1b52016-12-09 09:52:16 -0500969static u8 *
970format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100971{
972 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
973 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200975 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976
John Loac8146c2016-09-27 17:44:02 -0400977 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500978 t->fib_index, t->adj_index, t->flow_hash);
979 s = format (s, "\n%U%U",
980 format_white_space, indent,
981 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100982 return s;
983}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100984
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986static u8 *
987format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100988{
989 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
990 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200992 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100994 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 t->fib_index, t->adj_index, format_ip_adjacency,
996 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100997 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998 format_white_space, indent,
999 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001000 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001 return s;
1002}
1003
1004/* Common trace function for all ip6-forward next nodes. */
Damjan Marion38173502019-02-13 19:30:09 +01001005#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006void
1007ip6_forward_next_trace (vlib_main_t * vm,
1008 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011 u32 *from, n_left;
1012 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013
1014 n_left = frame->n_vectors;
1015 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001016
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017 while (n_left >= 4)
1018 {
1019 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020 vlib_buffer_t *b0, *b1;
1021 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001022
1023 /* Prefetch next iteration. */
1024 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1025 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1026
1027 bi0 = from[0];
1028 bi1 = from[1];
1029
1030 b0 = vlib_get_buffer (vm, bi0);
1031 b1 = vlib_get_buffer (vm, bi1);
1032
1033 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1034 {
1035 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1036 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001037 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1038 t0->fib_index =
1039 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1040 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1041 vec_elt (im->fib_index_by_sw_if_index,
1042 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001043
Dave Barach178cf492018-11-13 16:34:13 -05001044 clib_memcpy_fast (t0->packet_data,
1045 vlib_buffer_get_current (b0),
1046 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 }
1048 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1049 {
1050 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1051 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1053 t1->fib_index =
1054 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1055 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1056 vec_elt (im->fib_index_by_sw_if_index,
1057 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001058
Dave Barach178cf492018-11-13 16:34:13 -05001059 clib_memcpy_fast (t1->packet_data,
1060 vlib_buffer_get_current (b1),
1061 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
1063 from += 2;
1064 n_left -= 2;
1065 }
1066
1067 while (n_left >= 1)
1068 {
1069 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001070 vlib_buffer_t *b0;
1071 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
1073 bi0 = from[0];
1074
1075 b0 = vlib_get_buffer (vm, bi0);
1076
1077 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1078 {
1079 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1080 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001081 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1082 t0->fib_index =
1083 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1084 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1085 vec_elt (im->fib_index_by_sw_if_index,
1086 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001087
Dave Barach178cf492018-11-13 16:34:13 -05001088 clib_memcpy_fast (t0->packet_data,
1089 vlib_buffer_get_current (b0),
1090 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 }
1092 from += 1;
1093 n_left -= 1;
1094 }
1095}
1096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001098u16
1099ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1100 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101{
Matthew Smith97677a22020-02-05 11:46:40 -06001102 ip_csum_t sum0 = 0;
1103 u16 payload_length, payload_length_host_byte_order;
Srikanth A02833ff2019-10-02 17:48:58 -07001104 u32 i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001105 u32 headers_size = sizeof (ip0[0]);
Dave Barachc4abafd2019-09-04 12:09:32 -04001106 u8 *data_this_buffer;
Matthew Smith97677a22020-02-05 11:46:40 -06001107 u8 next_hdr = ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110 *bogus_lengthp = 0;
1111
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
Dave Barachc4abafd2019-09-04 12:09:32 -04001113 data_this_buffer = (u8 *) (ip0 + 1);
Matthew Smith97677a22020-02-05 11:46:40 -06001114 payload_length = ip0->payload_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301116 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1117 * or UDP-Ping packets */
Matthew Smith97677a22020-02-05 11:46:40 -06001118 if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001120 u32 skip_bytes;
1121 ip6_hop_by_hop_ext_t *ext_hdr =
1122 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123
1124 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301125 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1126 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1129 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001130
Dave Barachd7cb1b52016-12-09 09:52:16 -05001131 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 headers_size += skip_bytes;
Matthew Smith97677a22020-02-05 11:46:40 -06001133
1134 /* pseudo-header adjustments:
1135 * exclude ext header bytes from payload length
1136 * use payload IP proto rather than ext header IP proto
1137 */
1138 payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1139 next_hdr = ext_hdr->next_hdr;
1140 }
1141
1142 /* Initialize checksum with ip pseudo-header. */
1143 sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1144
1145 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1146 {
1147 sum0 = ip_csum_with_carry
1148 (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1149 sum0 = ip_csum_with_carry
1150 (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001151 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152
John Lo3bc6bc22019-08-03 14:36:39 -04001153 if (p0)
Srikanth A02833ff2019-10-02 17:48:58 -07001154 return ip_calculate_l4_checksum (vm, p0, sum0,
1155 payload_length_host_byte_order,
1156 (u8 *) ip0, headers_size, NULL);
1157 else
1158 return ip_calculate_l4_checksum (vm, 0, sum0,
1159 payload_length_host_byte_order, NULL, 0,
1160 data_this_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161}
1162
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163u32
1164ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001166 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1167 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 u16 sum16;
1169 int bogus_length;
1170
1171 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1172 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1173 || ip0->protocol == IP_PROTOCOL_ICMP6
1174 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001175 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176
1177 udp0 = (void *) (ip0 + 1);
1178 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1179 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001180 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1181 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 return p0->flags;
1183 }
1184
1185 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1186
Damjan Marion213b5aa2017-07-13 21:19:27 +02001187 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1188 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189
1190 return p0->flags;
1191}
Damjan Marion38173502019-02-13 19:30:09 +01001192#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301194/**
1195 * @brief returns number of links on which src is reachable.
1196 */
1197always_inline int
1198ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1199{
1200 const load_balance_t *lb0;
1201 index_t lbi;
Florin Corasf3a3bad2018-03-28 02:18:29 -07001202 u32 fib_index;
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301203
Florin Corasf3a3bad2018-03-28 02:18:29 -07001204 fib_index = vec_elt (im->fib_index_by_sw_if_index,
1205 vnet_buffer (b)->sw_if_index[VLIB_RX]);
1206 fib_index =
1207 (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1208 fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301209
Simon Zhange7eba482019-08-25 15:30:45 +08001210 lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301211 lb0 = load_balance_get (lbi);
1212
1213 return (fib_urpf_check_size (lb0->lb_urpf));
1214}
1215
rootc9d1c5b2017-08-15 12:58:31 -04001216always_inline u8
1217ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1218 u32 * udp_offset0)
1219{
1220 u32 proto0;
1221 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1222 if (proto0 != IP_PROTOCOL_UDP)
1223 {
1224 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1225 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1226 }
1227 return proto0;
1228}
1229
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001230/* *INDENT-OFF* */
1231VNET_FEATURE_ARC_INIT (ip6_local) =
1232{
1233 .arc_name = "ip6-local",
1234 .start_nodes = VNET_FEATURES ("ip6-local"),
1235};
1236/* *INDENT-ON* */
1237
johny17478e42019-10-11 18:28:51 +02001238static_always_inline u8
1239ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
1240{
1241
1242 u16 payload_length_host_byte_order;
1243 u32 n_this_buffer, n_bytes_left;
1244 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1245 u32 headers_size = sizeof (ip0[0]);
1246 u8 *data_this_buffer;
1247
1248
1249 data_this_buffer = (u8 *) (ip0 + 1);
1250
1251 ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1252
1253 /* validate really icmp6 next */
1254
1255 if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1256 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1257 return 0;
1258
1259
1260 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1261 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1262
johnya633a432019-12-06 13:58:35 +01001263
1264 u32 n_ip_bytes_this_buffer =
1265 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1266 if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
johny17478e42019-10-11 18:28:51 +02001267 {
johnya633a432019-12-06 13:58:35 +01001268 n_this_buffer = p0->current_length > headers_size ?
1269 n_ip_bytes_this_buffer - headers_size : 0;
johny17478e42019-10-11 18:28:51 +02001270 }
1271
1272 n_bytes_left -= n_this_buffer;
1273 n_bytes_left -= p0->total_length_not_including_first_buffer;
1274
1275 if (n_bytes_left == 0)
1276 return 0;
1277 else
1278 return 1;
1279}
1280
1281
Benoît Ganne26a10192019-02-14 15:32:45 +01001282always_inline uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001283ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1284 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 ip6_main_t *im = &ip6_main;
1287 ip_lookup_main_t *lm = &im->lookup_main;
Benoît Ganne26a10192019-02-14 15:32:45 +01001288 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 vlib_node_runtime_t *error_node =
1290 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001291 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001292 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1293 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294
1295 from = vlib_frame_vector_args (frame);
1296 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001297
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 if (node->flags & VLIB_NODE_FLAG_TRACE)
1299 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1300
Benoît Ganne26a10192019-02-14 15:32:45 +01001301 vlib_get_buffers (vm, from, bufs, n_left_from);
1302 b = bufs;
1303 next = nexts;
1304
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001305 while (n_left_from > 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001307 /* Prefetch next iteration. */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001308 if (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001310 vlib_prefetch_buffer_header (b[4], STORE);
1311 vlib_prefetch_buffer_header (b[5], STORE);
1312 vlib_prefetch_buffer_data (b[2], LOAD);
1313 vlib_prefetch_buffer_data (b[3], LOAD);
Benoît Ganne26a10192019-02-14 15:32:45 +01001314 }
Dave Barach75fc8542016-10-11 16:16:02 -04001315
Neale Rannsf6472e02020-12-18 09:42:18 +00001316 ip6_error_t error[2];
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001317 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1318 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
Dave Barach75fc8542016-10-11 16:16:02 -04001319
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001320 ip6_header_t *ip[2];
1321 ip[0] = vlib_buffer_get_current (b[0]);
1322 ip[1] = vlib_buffer_get_current (b[1]);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001323
Benoît Ganne26a10192019-02-14 15:32:45 +01001324 if (head_of_feature_arc)
1325 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001326 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1327 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001329 u8 type[2];
1330 type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1331 type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001333 u32 flags[2];
1334 flags[0] = b[0]->flags;
1335 flags[1] = b[1]->flags;
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001336
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +02001337 vnet_buffer_oflags_t oflags[2];
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001338 oflags[0] = vnet_buffer (b[0])->oflags;
1339 oflags[1] = vnet_buffer (b[1])->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +01001340
1341 u32 l4_offload[2];
1342 l4_offload[0] = (flags[0] & VNET_BUFFER_F_OFFLOAD) &&
1343 (oflags[0] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1344 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1345 l4_offload[1] = (flags[1] & VNET_BUFFER_F_OFFLOAD) &&
1346 (oflags[1] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1347 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1348
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001349 u32 good_l4_csum[2];
1350 good_l4_csum[0] =
Mohsin Kazmi68095382021-02-10 11:26:24 +01001351 (flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[0];
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001352 good_l4_csum[1] =
Mohsin Kazmi68095382021-02-10 11:26:24 +01001353 (flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[1];
Filip Tehlarb601f222017-01-02 10:22:56 +01001354
Damjan Marion34e823f2019-02-19 08:55:18 +01001355 u32 udp_offset[2] = { };
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001356 u8 is_tcp_udp[2];
1357 is_tcp_udp[0] =
1358 ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1359 is_tcp_udp[1] =
1360 ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1361 i16 len_diff[2] = { 0 };
1362 if (PREDICT_TRUE (is_tcp_udp[0]))
Shwethab78292e2016-09-13 11:51:00 +01001363 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001364 udp_header_t *udp =
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001365 (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1366 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
Benoît Ganne26a10192019-02-14 15:32:45 +01001367 && udp->checksum == 0;
1368 /* optimistically verify UDP length. */
1369 u16 ip_len, udp_len;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001370 ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
Benoît Ganne26a10192019-02-14 15:32:45 +01001371 udp_len = clib_net_to_host_u16 (udp->length);
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001372 len_diff[0] = ip_len - udp_len;
Shwethab78292e2016-09-13 11:51:00 +01001373 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001374 if (PREDICT_TRUE (is_tcp_udp[1]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001375 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001376 udp_header_t *udp =
1377 (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1378 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1379 && udp->checksum == 0;
1380 /* optimistically verify UDP length. */
1381 u16 ip_len, udp_len;
1382 ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1383 udp_len = clib_net_to_host_u16 (udp->length);
1384 len_diff[1] = ip_len - udp_len;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385 }
1386
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001387 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1388 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1389
1390 len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1391 len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1392
1393 u8 need_csum[2];
1394 need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1395 && !good_l4_csum[0]
1396 && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1397 need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1398 && !good_l4_csum[1]
1399 && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1400 if (PREDICT_FALSE (need_csum[0]))
1401 {
1402 flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1403 good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001404 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1405 }
1406 else
1407 {
1408 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1409 error[0] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001410 }
1411 if (PREDICT_FALSE (need_csum[1]))
1412 {
1413 flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1414 good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001415 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1416 }
1417 else
1418 {
1419 if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1420 error[1] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001421 }
1422
johny17478e42019-10-11 18:28:51 +02001423
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001424 error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
johny17478e42019-10-11 18:28:51 +02001425
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001426 error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001427
Benoît Ganne26a10192019-02-14 15:32:45 +01001428 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1429 IP6_ERROR_UDP_CHECKSUM,
1430 "Wrong IP6 errors constants");
1431 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1432 IP6_ERROR_ICMP_CHECKSUM,
1433 "Wrong IP6 errors constants");
1434
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001435 error[0] =
1436 !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1437 error[1] =
1438 !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439
1440 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001441 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001442 u8 unroutable[2];
1443 unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1444 && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1445 && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
1446 unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1447 && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1448 && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
1449 if (PREDICT_FALSE (unroutable[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001451 error[0] =
1452 !ip6_urpf_loose_check (im, b[0],
1453 ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1454 : error[0];
1455 }
1456 if (PREDICT_FALSE (unroutable[1]))
1457 {
1458 error[1] =
1459 !ip6_urpf_loose_check (im, b[1],
1460 ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1461 : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001462 }
1463
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001464 vnet_buffer (b[0])->ip.fib_index =
1465 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1466 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1467 vnet_buffer (b[0])->ip.fib_index;
1468 vnet_buffer (b[1])->ip.fib_index =
1469 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1470 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1471 vnet_buffer (b[1])->ip.fib_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001472 } /* head_of_feature_arc */
Florin Corascea194d2017-10-02 00:18:51 -07001473
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001474 next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1475 next[0] =
1476 error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1477 next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1478 next[1] =
1479 error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
Florin Corascea194d2017-10-02 00:18:51 -07001480
Benoît Gannec15539a2021-01-19 16:40:07 +01001481 b[0]->error = error_node->errors[error[0]];
1482 b[1]->error = error_node->errors[error[1]];
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001483
Benoît Ganne26a10192019-02-14 15:32:45 +01001484 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001485 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001486 u8 ip6_unknown[2];
1487 ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1488 ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1489 if (PREDICT_TRUE (ip6_unknown[0]))
Shwethab78292e2016-09-13 11:51:00 +01001490 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001491 u32 next32 = next[0];
Benoît Ganne26a10192019-02-14 15:32:45 +01001492 vnet_feature_arc_start (arc_index,
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001493 vnet_buffer (b[0])->sw_if_index
1494 [VLIB_RX], &next32, b[0]);
1495 next[0] = next32;
1496 }
1497 if (PREDICT_TRUE (ip6_unknown[1]))
1498 {
1499 u32 next32 = next[1];
1500 vnet_feature_arc_start (arc_index,
1501 vnet_buffer (b[1])->sw_if_index
1502 [VLIB_RX], &next32, b[1]);
1503 next[1] = next32;
Shwethab78292e2016-09-13 11:51:00 +01001504 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001505 }
Dave Barach75fc8542016-10-11 16:16:02 -04001506
Benoît Ganne26a10192019-02-14 15:32:45 +01001507 /* next */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001508 b += 2;
1509 next += 2;
1510 n_left_from -= 2;
Benoît Ganne26a10192019-02-14 15:32:45 +01001511 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001512
Benoît Ganne26a10192019-02-14 15:32:45 +01001513 while (n_left_from)
1514 {
1515 u8 error;
1516 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1517
1518 ip6_header_t *ip;
1519 ip = vlib_buffer_get_current (b[0]);
1520
1521 if (head_of_feature_arc)
1522 {
1523 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1524 u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
1525
1526 u32 flags = b[0]->flags;
Benoît Ganne26a10192019-02-14 15:32:45 +01001527
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +02001528 vnet_buffer_oflags_t oflags = vnet_buffer (b[0])->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +01001529
1530 u32 l4_offload = (flags & VNET_BUFFER_F_OFFLOAD) &&
1531 (oflags & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1532 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1533
1534 u32 good_l4_csum =
1535 (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload;
Benoît Ganne26a10192019-02-14 15:32:45 +01001536 u32 udp_offset;
1537 i16 len_diff = 0;
1538 u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1539 if (PREDICT_TRUE (is_tcp_udp))
1540 {
1541 udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1542 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1543 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1544 && udp->checksum == 0;
1545 /* optimistically verify UDP length. */
1546 u16 ip_len, udp_len;
1547 ip_len = clib_net_to_host_u16 (ip->payload_length);
1548 udp_len = clib_net_to_host_u16 (udp->length);
1549 len_diff = ip_len - udp_len;
1550 }
1551
1552 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1553 len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1554
Mohsin Kazmi68095382021-02-10 11:26:24 +01001555 u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN &&
1556 !good_l4_csum &&
1557 !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
Benoît Ganne26a10192019-02-14 15:32:45 +01001558 if (PREDICT_FALSE (need_csum))
1559 {
1560 flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1561 good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001562 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1563 }
1564 else
1565 {
1566 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1567 error = IP6_ERROR_BAD_LENGTH;
Benoît Ganne26a10192019-02-14 15:32:45 +01001568 }
1569
johny17478e42019-10-11 18:28:51 +02001570
1571
Benoît Ganne26a10192019-02-14 15:32:45 +01001572 error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
Benoît Ganne26a10192019-02-14 15:32:45 +01001573 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1574 IP6_ERROR_UDP_CHECKSUM,
1575 "Wrong IP6 errors constants");
1576 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1577 IP6_ERROR_ICMP_CHECKSUM,
1578 "Wrong IP6 errors constants");
1579
1580 error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1581
1582 /* Drop packets from unroutable hosts. */
1583 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1584 u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1585 && type != IP_BUILTIN_PROTOCOL_ICMP
1586 && !ip6_address_is_link_local_unicast (&ip->src_address);
1587 if (PREDICT_FALSE (unroutable))
1588 {
1589 error =
1590 !ip6_urpf_loose_check (im, b[0],
1591 ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1592 error;
1593 }
1594
1595 vnet_buffer (b[0])->ip.fib_index =
1596 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1597 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1598 vnet_buffer (b[0])->ip.fib_index;
1599 } /* head_of_feature_arc */
1600
1601 next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1602 next[0] =
1603 error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1604
Benoît Gannec15539a2021-01-19 16:40:07 +01001605 b[0]->error = error_node->errors[error];
Benoît Ganne26a10192019-02-14 15:32:45 +01001606
1607 if (head_of_feature_arc)
1608 {
1609 if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1610 {
1611 u32 next32 = next[0];
1612 vnet_feature_arc_start (arc_index,
1613 vnet_buffer (b[0])->sw_if_index
1614 [VLIB_RX], &next32, b[0]);
1615 next[0] = next32;
1616 }
1617 }
1618
1619 /* next */
1620 b += 1;
1621 next += 1;
1622 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623 }
1624
Benoît Ganne26a10192019-02-14 15:32:45 +01001625 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 return frame->n_vectors;
1627}
1628
Damjan Marion38173502019-02-13 19:30:09 +01001629VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1630 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001631{
1632 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1633}
1634
Dave Barachd7cb1b52016-12-09 09:52:16 -05001635/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001636VLIB_REGISTER_NODE (ip6_local_node) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001637{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001638 .name = "ip6-local",
1639 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001640 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 .next_nodes =
1643 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001644 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1645 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1647 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001648 [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649 },
1650};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001651/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652
Damjan Marion38173502019-02-13 19:30:09 +01001653VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
1654 vlib_node_runtime_t * node,
1655 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001656{
1657 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1658}
1659
1660/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001661VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001662 .name = "ip6-local-end-of-arc",
1663 .vector_size = sizeof (u32),
1664
1665 .format_trace = format_ip6_forward_next_trace,
1666 .sibling_of = "ip6-local",
1667};
1668
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001669VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1670 .arc_name = "ip6-local",
1671 .node_name = "ip6-local-end-of-arc",
1672 .runs_before = 0, /* not before any other features */
1673};
1674/* *INDENT-ON* */
1675
Damjan Marion38173502019-02-13 19:30:09 +01001676#ifdef CLIB_MARCH_VARIANT
1677extern vlib_node_registration_t ip6_local_node;
Damjan Marion38173502019-02-13 19:30:09 +01001678#else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679void
1680ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001681{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001682 vlib_main_t *vm = vlib_get_main ();
1683 ip6_main_t *im = &ip6_main;
1684 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685
1686 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001687 lm->local_next_by_ip_protocol[protocol] =
1688 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689}
1690
Neale Rannsb538dd82019-05-21 06:54:54 -07001691void
1692ip6_unregister_protocol (u32 protocol)
1693{
1694 ip6_main_t *im = &ip6_main;
1695 ip_lookup_main_t *lm = &im->lookup_main;
1696
1697 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1698 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1699}
Damjan Marion38173502019-02-13 19:30:09 +01001700#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001701
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702typedef enum
1703{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001704 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001705 IP6_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001706 IP6_REWRITE_NEXT_FRAGMENT,
1707 IP6_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708} ip6_rewrite_next_t;
1709
Neale Ranns889fe942017-06-01 05:43:19 -04001710/**
1711 * This bits of an IPv6 address to mask to construct a multicast
1712 * MAC address
1713 */
1714#define IP6_MCAST_ADDR_MASK 0xffffffff
1715
Ole Troanda6e11b2018-05-23 11:21:42 +02001716always_inline void
1717ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
Ole Troan313f7e22018-04-10 16:02:51 +02001718 u16 adj_packet_bytes, bool is_locally_generated,
Ole Troaneb284a12019-10-09 13:33:19 +02001719 u32 * next, u8 is_midchain, u32 * error)
Ole Troanda6e11b2018-05-23 11:21:42 +02001720{
1721 if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1722 {
Ole Troan313f7e22018-04-10 16:02:51 +02001723 if (is_locally_generated)
1724 {
1725 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02001726 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001727 (is_midchain ?
1728 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1729 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02001730 *next = IP6_REWRITE_NEXT_FRAGMENT;
Ole Troan282093f2018-09-19 12:38:51 +02001731 *error = IP6_ERROR_MTU_EXCEEDED;
Ole Troan313f7e22018-04-10 16:02:51 +02001732 }
1733 else
1734 {
1735 *error = IP6_ERROR_MTU_EXCEEDED;
1736 icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1737 adj_packet_bytes);
1738 *next = IP6_REWRITE_NEXT_ICMP_ERROR;
1739 }
Ole Troanda6e11b2018-05-23 11:21:42 +02001740 }
1741}
1742
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001744ip6_rewrite_inline_with_gso (vlib_main_t * vm,
1745 vlib_node_runtime_t * node,
1746 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001747 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001748{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1750 u32 *from = vlib_frame_vector_args (frame);
1751 u32 n_left_from, n_left_to_next, *to_next, next_index;
1752 vlib_node_runtime_t *error_node =
1753 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754
1755 n_left_from = frame->n_vectors;
1756 next_index = node->cached_next_index;
Damjan Marion067cd622018-07-11 12:47:43 +02001757 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001758
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 while (n_left_from > 0)
1760 {
1761 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1762
1763 while (n_left_from >= 4 && n_left_to_next >= 2)
1764 {
Neale Ranns960eeea2019-12-02 23:28:50 +00001765 const ip_adjacency_t *adj0, *adj1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001766 vlib_buffer_t *p0, *p1;
1767 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 u32 pi0, rw_len0, next0, error0, adj_index0;
1769 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 u32 tx_sw_if_index0, tx_sw_if_index1;
Ole Troan313f7e22018-04-10 16:02:51 +02001771 bool is_locally_originated0, is_locally_originated1;
Dave Barach75fc8542016-10-11 16:16:02 -04001772
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 /* Prefetch next iteration. */
1774 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001775 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001776
1777 p2 = vlib_get_buffer (vm, from[2]);
1778 p3 = vlib_get_buffer (vm, from[3]);
1779
1780 vlib_prefetch_buffer_header (p2, LOAD);
1781 vlib_prefetch_buffer_header (p3, LOAD);
1782
Damjan Marionaf7fb042021-07-15 11:54:41 +02001783 clib_prefetch_store (p2->pre_data);
1784 clib_prefetch_store (p3->pre_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001785
1786 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1787 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1788 }
1789
1790 pi0 = to_next[0] = from[0];
1791 pi1 = to_next[1] = from[1];
1792
1793 from += 2;
1794 n_left_from -= 2;
1795 to_next += 2;
1796 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001797
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798 p0 = vlib_get_buffer (vm, pi0);
1799 p1 = vlib_get_buffer (vm, pi1);
1800
Neale Rannsf06aea52016-11-29 06:51:37 -08001801 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1802 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804 ip0 = vlib_buffer_get_current (p0);
1805 ip1 = vlib_buffer_get_current (p1);
1806
1807 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001808 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809
Ole Troan313f7e22018-04-10 16:02:51 +02001810 is_locally_originated0 =
1811 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1812 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001814 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815
1816 /* Input node should have reject packets with hop limit 0. */
1817 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818
1819 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001820
1821 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001822
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 /*
1824 * If the hop count drops below 1 when forwarding, generate
1825 * an ICMP response.
1826 */
1827 if (PREDICT_FALSE (hop_limit0 <= 0))
1828 {
1829 error0 = IP6_ERROR_TIME_EXPIRED;
1830 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1831 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1832 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1833 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1834 0);
1835 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001836 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001837
Ole Troan313f7e22018-04-10 16:02:51 +02001838 is_locally_originated1 =
1839 p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1840 if (PREDICT_TRUE (!is_locally_originated1))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001842 i32 hop_limit1 = ip1->hop_limit;
1843
1844 /* Input node should have reject packets with hop limit 0. */
1845 ASSERT (ip1->hop_limit > 0);
1846
1847 hop_limit1 -= 1;
1848
1849 ip1->hop_limit = hop_limit1;
1850
Dave Barachd7cb1b52016-12-09 09:52:16 -05001851 /*
1852 * If the hop count drops below 1 when forwarding, generate
1853 * an ICMP response.
1854 */
1855 if (PREDICT_FALSE (hop_limit1 <= 0))
1856 {
1857 error1 = IP6_ERROR_TIME_EXPIRED;
1858 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1859 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1860 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1861 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1862 0);
1863 }
1864 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001865
Neale Ranns107e7d42017-04-11 09:55:19 -07001866 adj0 = adj_get (adj_index0);
1867 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868
Ed Warnickecb9cada2015-12-08 15:45:58 -07001869 rw_len0 = adj0[0].rewrite_header.data_bytes;
1870 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001871 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1872 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873
Neale Ranns9c6a6132017-02-21 05:33:14 -08001874 if (do_counters)
1875 {
1876 vlib_increment_combined_counter
1877 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001878 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001879 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1880 vlib_increment_combined_counter
1881 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001882 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001883 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1884 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885
1886 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001887 u16 ip0_len =
1888 clib_net_to_host_u16 (ip0->payload_length) +
1889 sizeof (ip6_header_t);
1890 u16 ip1_len =
1891 clib_net_to_host_u16 (ip1->payload_length) +
1892 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001893 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001894 ip0_len = gso_mtu_sz (p0);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001895 if (p1->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001896 ip1_len = gso_mtu_sz (p1);
1897
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001898 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001899 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001900 is_locally_originated0, &next0, is_midchain,
1901 &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001902 ip6_mtu_check (p1, ip1_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001903 adj1[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001904 is_locally_originated1, &next1, is_midchain,
1905 &error1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001906 /* Don't adjust the buffer for hop count issue; icmp-error node
Jim Thompsonf324dec2019-04-08 03:22:21 -05001907 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1909 {
1910 p0->current_data -= rw_len0;
1911 p0->current_length += rw_len0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001912 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1913 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1914 next0 = adj0[0].rewrite_header.next_index;
Neale Rannsb069a692017-03-15 12:34:25 -04001915 if (PREDICT_FALSE
1916 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001917 vnet_feature_arc_start_w_cfg_index
1918 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
1919 adj0->ia_cfg_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001920 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001921 else
1922 {
1923 p0->error = error_node->errors[error0];
1924 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001925 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1926 {
1927 p1->current_data -= rw_len1;
1928 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001929
Dave Barachd7cb1b52016-12-09 09:52:16 -05001930 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1931 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1932 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001933
Neale Rannsb069a692017-03-15 12:34:25 -04001934 if (PREDICT_FALSE
1935 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001936 vnet_feature_arc_start_w_cfg_index
1937 (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1,
1938 adj1->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001939 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001940 else
1941 {
1942 p1->error = error_node->errors[error1];
1943 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944
Neale Ranns25edf142019-03-22 08:12:48 +00001945 if (is_midchain)
1946 {
1947 /* before we paint on the next header, update the L4
1948 * checksums if required, since there's no offload on a tunnel */
Dave Barach1bd2c012020-04-12 08:31:39 -04001949 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001950 1 /* is_ip6 */ );
Dave Barach1bd2c012020-04-12 08:31:39 -04001951 vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001952 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00001953
Neale Ranns4ec36c52020-03-31 09:21:29 -04001954 /* Guess we are only writing on ipv6 header. */
1955 vnet_rewrite_two_headers (adj0[0], adj1[0],
1956 ip0, ip1, sizeof (ip6_header_t));
1957 }
1958 else
1959 /* Guess we are only writing on simple Ethernet header. */
1960 vnet_rewrite_two_headers (adj0[0], adj1[0],
1961 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001962
1963 if (is_midchain)
1964 {
Neale Ranns25edf142019-03-22 08:12:48 +00001965 if (adj0->sub_type.midchain.fixup_func)
1966 adj0->sub_type.midchain.fixup_func
1967 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1968 if (adj1->sub_type.midchain.fixup_func)
1969 adj1->sub_type.midchain.fixup_func
1970 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001971 }
1972 if (is_mcast)
1973 {
1974 /*
1975 * copy bytes from the IP address into the MAC rewrite
1976 */
Neale Ranns889fe942017-06-01 05:43:19 -04001977 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1978 adj0->
1979 rewrite_header.dst_mcast_offset,
1980 &ip0->dst_address.as_u32[3],
1981 (u8 *) ip0);
1982 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1983 adj1->
1984 rewrite_header.dst_mcast_offset,
1985 &ip1->dst_address.as_u32[3],
1986 (u8 *) ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001987 }
Neale Ranns5e575b12016-10-03 09:40:25 +01001988
Ed Warnickecb9cada2015-12-08 15:45:58 -07001989 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1990 to_next, n_left_to_next,
1991 pi0, pi1, next0, next1);
1992 }
1993
1994 while (n_left_from > 0 && n_left_to_next > 0)
1995 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001996 ip_adjacency_t *adj0;
1997 vlib_buffer_t *p0;
1998 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001999 u32 pi0, rw_len0;
2000 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002001 u32 tx_sw_if_index0;
Ole Troan313f7e22018-04-10 16:02:51 +02002002 bool is_locally_originated0;
Dave Barach75fc8542016-10-11 16:16:02 -04002003
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004 pi0 = to_next[0] = from[0];
2005
2006 p0 = vlib_get_buffer (vm, pi0);
2007
Neale Rannsf06aea52016-11-29 06:51:37 -08002008 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009
Neale Ranns107e7d42017-04-11 09:55:19 -07002010 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002011
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 ip0 = vlib_buffer_get_current (p0);
2013
2014 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002015 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016
2017 /* Check hop limit */
Ole Troan313f7e22018-04-10 16:02:51 +02002018 is_locally_originated0 =
2019 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
2020 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021 {
2022 i32 hop_limit0 = ip0->hop_limit;
2023
2024 ASSERT (ip0->hop_limit > 0);
2025
2026 hop_limit0 -= 1;
2027
2028 ip0->hop_limit = hop_limit0;
2029
Dave Barachd7cb1b52016-12-09 09:52:16 -05002030 if (PREDICT_FALSE (hop_limit0 <= 0))
2031 {
2032 /*
2033 * If the hop count drops below 1 when forwarding, generate
2034 * an ICMP response.
2035 */
2036 error0 = IP6_ERROR_TIME_EXPIRED;
2037 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2038 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2039 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2040 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2041 0);
2042 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002043 }
2044
Neale Ranns25edf142019-03-22 08:12:48 +00002045 if (is_midchain)
2046 {
Dave Barach1bd2c012020-04-12 08:31:39 -04002047 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002048 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00002049
Neale Ranns4ec36c52020-03-31 09:21:29 -04002050 /* Guess we are only writing on ip6 header. */
2051 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t));
2052 }
2053 else
2054 /* Guess we are only writing on simple Ethernet header. */
2055 vnet_rewrite_one_header (adj0[0], ip0,
2056 sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002057
Ed Warnickecb9cada2015-12-08 15:45:58 -07002058 /* Update packet buffer attributes/set output interface. */
2059 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002060 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002061
Neale Ranns9c6a6132017-02-21 05:33:14 -08002062 if (do_counters)
2063 {
2064 vlib_increment_combined_counter
2065 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002066 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002067 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2068 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069
2070 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002071 u16 ip0_len =
2072 clib_net_to_host_u16 (ip0->payload_length) +
2073 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002074 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002075 ip0_len = gso_mtu_sz (p0);
2076
2077 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02002078 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02002079 is_locally_originated0, &next0, is_midchain,
2080 &error0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002081 /* Don't adjust the buffer for hop count issue; icmp-error node
Ole Troanda6e11b2018-05-23 11:21:42 +02002082 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002083 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2084 {
Chris Luke816f3e12016-06-14 16:24:47 -04002085 p0->current_data -= rw_len0;
2086 p0->current_length += rw_len0;
2087
Dave Barachd7cb1b52016-12-09 09:52:16 -05002088 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002089
Dave Barachd7cb1b52016-12-09 09:52:16 -05002090 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2091 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002092
Neale Rannsb069a692017-03-15 12:34:25 -04002093 if (PREDICT_FALSE
2094 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002095 vnet_feature_arc_start_w_cfg_index
2096 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
2097 adj0->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002098 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002099 else
2100 {
2101 p0->error = error_node->errors[error0];
2102 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002104 if (is_midchain)
2105 {
Neale Ranns25edf142019-03-22 08:12:48 +00002106 if (adj0->sub_type.midchain.fixup_func)
2107 adj0->sub_type.midchain.fixup_func
2108 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002109 }
2110 if (is_mcast)
2111 {
Neale Ranns889fe942017-06-01 05:43:19 -04002112 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2113 adj0->
2114 rewrite_header.dst_mcast_offset,
2115 &ip0->dst_address.as_u32[3],
2116 (u8 *) ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002117 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002118
Ed Warnickecb9cada2015-12-08 15:45:58 -07002119 from += 1;
2120 n_left_from -= 1;
2121 to_next += 1;
2122 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002123
Ed Warnickecb9cada2015-12-08 15:45:58 -07002124 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2125 to_next, n_left_to_next,
2126 pi0, next0);
2127 }
2128
2129 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2130 }
2131
2132 /* Need to do trace after rewrites to pick up new packet data. */
2133 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002134 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002135
2136 return frame->n_vectors;
2137}
2138
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002139always_inline uword
2140ip6_rewrite_inline (vlib_main_t * vm,
2141 vlib_node_runtime_t * node,
2142 vlib_frame_t * frame,
2143 int do_counters, int is_midchain, int is_mcast)
2144{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002145 return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2146 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002147}
2148
Damjan Marion38173502019-02-13 19:30:09 +01002149VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
2150 vlib_node_runtime_t * node,
2151 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002153 if (adj_are_counters_enabled ())
2154 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2155 else
2156 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002157}
2158
Damjan Marion38173502019-02-13 19:30:09 +01002159VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
2160 vlib_node_runtime_t * node,
2161 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002162{
2163 if (adj_are_counters_enabled ())
2164 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2165 else
2166 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2167}
2168
Damjan Marion38173502019-02-13 19:30:09 +01002169VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
2170 vlib_node_runtime_t * node,
2171 vlib_frame_t * frame)
Neale Ranns32e1c012016-11-22 17:07:28 +00002172{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002173 if (adj_are_counters_enabled ())
2174 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2175 else
2176 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002177}
2178
Damjan Marion38173502019-02-13 19:30:09 +01002179VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
2180 vlib_node_runtime_t * node,
2181 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002182{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002183 if (adj_are_counters_enabled ())
2184 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2185 else
2186 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002187}
2188
Damjan Marion38173502019-02-13 19:30:09 +01002189VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
2190 vlib_node_runtime_t * node,
2191 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002192{
2193 if (adj_are_counters_enabled ())
2194 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2195 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002196 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002197}
2198
Dave Barachd7cb1b52016-12-09 09:52:16 -05002199/* *INDENT-OFF* */
2200VLIB_REGISTER_NODE (ip6_midchain_node) =
2201{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002202 .name = "ip6-midchain",
2203 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002204 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002205 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002206 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002207
Dave Barachd7cb1b52016-12-09 09:52:16 -05002208VLIB_REGISTER_NODE (ip6_rewrite_node) =
2209{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210 .name = "ip6-rewrite",
2211 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002212 .format_trace = format_ip6_rewrite_trace,
Ole Troan313f7e22018-04-10 16:02:51 +02002213 .n_next_nodes = IP6_REWRITE_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002214 .next_nodes =
2215 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002216 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002217 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002218 [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002219 },
2220};
2221
Neale Ranns1855b8e2018-07-11 10:31:26 -07002222VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002223 .name = "ip6-rewrite-bcast",
2224 .vector_size = sizeof (u32),
2225
2226 .format_trace = format_ip6_rewrite_trace,
2227 .sibling_of = "ip6-rewrite",
2228};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002229
Neale Ranns32e1c012016-11-22 17:07:28 +00002230VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2231{
Neale Ranns32e1c012016-11-22 17:07:28 +00002232 .name = "ip6-rewrite-mcast",
2233 .vector_size = sizeof (u32),
2234 .format_trace = format_ip6_rewrite_trace,
2235 .sibling_of = "ip6-rewrite",
2236};
Neale Ranns32e1c012016-11-22 17:07:28 +00002237
Neale Ranns32e1c012016-11-22 17:07:28 +00002238
Damjan Marion38173502019-02-13 19:30:09 +01002239VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002240{
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002241 .name = "ip6-mcast-midchain",
2242 .vector_size = sizeof (u32),
2243 .format_trace = format_ip6_rewrite_trace,
2244 .sibling_of = "ip6-rewrite",
2245};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002246
Neale Ranns1855b8e2018-07-11 10:31:26 -07002247/* *INDENT-ON* */
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002248
Ole Troan944f5482016-05-24 11:56:58 +02002249/*
2250 * Hop-by-Hop handling
2251 */
Benoît Ganne47727c02019-02-12 13:35:08 +01002252#ifndef CLIB_MARCH_VARIANT
Ole Troan944f5482016-05-24 11:56:58 +02002253ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01002254#endif /* CLIB_MARCH_VARIANT */
Ole Troan944f5482016-05-24 11:56:58 +02002255
2256#define foreach_ip6_hop_by_hop_error \
2257_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2258_(FORMAT, "incorrectly formatted hop-by-hop options") \
2259_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2260
Neale Ranns32e1c012016-11-22 17:07:28 +00002261/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002262typedef enum
2263{
Ole Troan944f5482016-05-24 11:56:58 +02002264#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2265 foreach_ip6_hop_by_hop_error
2266#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002267 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002268} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002269/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002270
2271/*
2272 * Primary h-b-h handler trace support
2273 * We work pretty hard on the problem for obvious reasons
2274 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002275typedef struct
2276{
Ole Troan944f5482016-05-24 11:56:58 +02002277 u32 next_index;
2278 u32 trace_len;
2279 u8 option_data[256];
2280} ip6_hop_by_hop_trace_t;
2281
Benoît Ganne47727c02019-02-12 13:35:08 +01002282extern vlib_node_registration_t ip6_hop_by_hop_node;
Ole Troan944f5482016-05-24 11:56:58 +02002283
Dave Barachd7cb1b52016-12-09 09:52:16 -05002284static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002285#define _(sym,string) string,
2286 foreach_ip6_hop_by_hop_error
2287#undef _
2288};
2289
Damjan Marion38173502019-02-13 19:30:09 +01002290#ifndef CLIB_MARCH_VARIANT
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302291u8 *
2292format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2293{
2294 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2295 int total_len = va_arg (*args, int);
2296 ip6_hop_by_hop_option_t *opt0, *limit0;
2297 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2298 u8 type0;
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302299 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2300 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2301
2302 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2303 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2304
2305 while (opt0 < limit0)
2306 {
2307 type0 = opt0->type;
2308 switch (type0)
2309 {
2310 case 0: /* Pad, just stop */
2311 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2312 break;
2313
2314 default:
2315 if (hm->trace[type0])
2316 {
2317 s = (*hm->trace[type0]) (s, opt0);
2318 }
2319 else
2320 {
Mohsin Kazmi68095382021-02-10 11:26:24 +01002321 s = format (s, "\n unrecognized option %d length %d", type0,
2322 opt0->length);
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302323 }
2324 opt0 =
2325 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2326 sizeof (ip6_hop_by_hop_option_t));
2327 break;
2328 }
2329 }
2330 return s;
2331}
Damjan Marion38173502019-02-13 19:30:09 +01002332#endif
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302333
Ole Troan944f5482016-05-24 11:56:58 +02002334static u8 *
2335format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2336{
2337 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2338 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002339 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002340 ip6_hop_by_hop_header_t *hbh0;
2341 ip6_hop_by_hop_option_t *opt0, *limit0;
2342 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2343
2344 u8 type0;
2345
Dave Barachd7cb1b52016-12-09 09:52:16 -05002346 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002347
2348 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002349 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002350
Dave Barachd7cb1b52016-12-09 09:52:16 -05002351 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2352 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002353
Dave Barachd7cb1b52016-12-09 09:52:16 -05002354 while (opt0 < limit0)
2355 {
2356 type0 = opt0->type;
2357 switch (type0)
2358 {
2359 case 0: /* Pad, just stop */
2360 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2361 break;
Ole Troan944f5482016-05-24 11:56:58 +02002362
Dave Barachd7cb1b52016-12-09 09:52:16 -05002363 default:
2364 if (hm->trace[type0])
2365 {
2366 s = (*hm->trace[type0]) (s, opt0);
2367 }
2368 else
2369 {
Mohsin Kazmi68095382021-02-10 11:26:24 +01002370 s = format (s, "\n unrecognized option %d length %d", type0,
2371 opt0->length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002372 }
2373 opt0 =
2374 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2375 sizeof (ip6_hop_by_hop_option_t));
2376 break;
2377 }
Ole Troan944f5482016-05-24 11:56:58 +02002378 }
Ole Troan944f5482016-05-24 11:56:58 +02002379 return s;
2380}
2381
Dave Barachd7cb1b52016-12-09 09:52:16 -05002382always_inline u8
2383ip6_scan_hbh_options (vlib_buffer_t * b0,
2384 ip6_header_t * ip0,
2385 ip6_hop_by_hop_header_t * hbh0,
2386 ip6_hop_by_hop_option_t * opt0,
2387 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002388{
2389 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2390 u8 type0;
2391 u8 error0 = 0;
2392
2393 while (opt0 < limit0)
2394 {
2395 type0 = opt0->type;
2396 switch (type0)
2397 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002398 case 0: /* Pad1 */
2399 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002400 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002401 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002402 break;
2403 default:
2404 if (hm->options[type0])
2405 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002406 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2407 {
Shwethaa91cbe62016-08-08 15:51:04 +01002408 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002409 return (error0);
2410 }
Shwethaa91cbe62016-08-08 15:51:04 +01002411 }
2412 else
2413 {
2414 /* Unrecognized mandatory option, check the two high order bits */
2415 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2416 {
2417 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2418 break;
2419 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2420 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2421 *next0 = IP_LOOKUP_NEXT_DROP;
2422 break;
2423 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2424 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2425 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002426 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2427 ICMP6_parameter_problem_unrecognized_option,
2428 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002429 break;
2430 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2431 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002432 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002433 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002434 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2435 icmp6_error_set_vnet_buffer (b0,
2436 ICMP6_parameter_problem,
2437 ICMP6_parameter_problem_unrecognized_option,
2438 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002439 }
2440 else
2441 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002442 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002443 }
2444 break;
2445 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002446 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002447 }
2448 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002449 opt0 =
2450 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2451 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002452 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002453 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002454}
2455
Ole Troan944f5482016-05-24 11:56:58 +02002456/*
2457 * Process the Hop-by-Hop Options header
2458 */
Damjan Marion38173502019-02-13 19:30:09 +01002459VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
2460 vlib_node_runtime_t * node,
2461 vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002462{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002463 vlib_node_runtime_t *error_node =
2464 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002465 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2466 u32 n_left_from, *from, *to_next;
2467 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002468
2469 from = vlib_frame_vector_args (frame);
2470 n_left_from = frame->n_vectors;
2471 next_index = node->cached_next_index;
2472
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473 while (n_left_from > 0)
2474 {
2475 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002476
Dave Barachd7cb1b52016-12-09 09:52:16 -05002477 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002478
Dave Barachd7cb1b52016-12-09 09:52:16 -05002479 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002480 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002481 u32 bi0, bi1;
2482 vlib_buffer_t *b0, *b1;
2483 u32 next0, next1;
2484 ip6_header_t *ip0, *ip1;
2485 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2486 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2487 u8 error0 = 0, error1 = 0;
2488
2489 /* Prefetch next iteration. */
2490 {
2491 vlib_buffer_t *p2, *p3;
2492
2493 p2 = vlib_get_buffer (vm, from[2]);
2494 p3 = vlib_get_buffer (vm, from[3]);
2495
2496 vlib_prefetch_buffer_header (p2, LOAD);
2497 vlib_prefetch_buffer_header (p3, LOAD);
2498
2499 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2500 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002501 }
2502
Dave Barachd7cb1b52016-12-09 09:52:16 -05002503 /* Speculatively enqueue b0, b1 to the current next frame */
2504 to_next[0] = bi0 = from[0];
2505 to_next[1] = bi1 = from[1];
2506 from += 2;
2507 to_next += 2;
2508 n_left_from -= 2;
2509 n_left_to_next -= 2;
2510
2511 b0 = vlib_get_buffer (vm, bi0);
2512 b1 = vlib_get_buffer (vm, bi1);
2513
2514 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2515 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002516 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002517 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002518 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519
2520 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2521 next0 = adj0->lookup_next_index;
2522 next1 = adj1->lookup_next_index;
2523
2524 ip0 = vlib_buffer_get_current (b0);
2525 ip1 = vlib_buffer_get_current (b1);
2526 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2527 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2528 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2529 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2530 limit0 =
2531 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2532 ((hbh0->length + 1) << 3));
2533 limit1 =
2534 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2535 ((hbh1->length + 1) << 3));
2536
2537 /*
2538 * Basic validity checks
2539 */
2540 if ((hbh0->length + 1) << 3 >
2541 clib_net_to_host_u16 (ip0->payload_length))
2542 {
2543 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2544 next0 = IP_LOOKUP_NEXT_DROP;
2545 goto outdual;
2546 }
2547 /* Scan the set of h-b-h options, process ones that we understand */
2548 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2549
2550 if ((hbh1->length + 1) << 3 >
2551 clib_net_to_host_u16 (ip1->payload_length))
2552 {
2553 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2554 next1 = IP_LOOKUP_NEXT_DROP;
2555 goto outdual;
2556 }
2557 /* Scan the set of h-b-h options, process ones that we understand */
2558 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2559
2560 outdual:
2561 /* Has the classifier flagged this buffer for special treatment? */
2562 if (PREDICT_FALSE
2563 ((error0 == 0)
2564 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2565 next0 = hm->next_override;
2566
2567 /* Has the classifier flagged this buffer for special treatment? */
2568 if (PREDICT_FALSE
2569 ((error1 == 0)
2570 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2571 next1 = hm->next_override;
2572
2573 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2574 {
2575 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2576 {
2577 ip6_hop_by_hop_trace_t *t =
2578 vlib_add_trace (vm, node, b0, sizeof (*t));
2579 u32 trace_len = (hbh0->length + 1) << 3;
2580 t->next_index = next0;
2581 /* Capture the h-b-h option verbatim */
2582 trace_len =
2583 trace_len <
2584 ARRAY_LEN (t->option_data) ? trace_len :
2585 ARRAY_LEN (t->option_data);
2586 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002587 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002588 }
2589 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2590 {
2591 ip6_hop_by_hop_trace_t *t =
2592 vlib_add_trace (vm, node, b1, sizeof (*t));
2593 u32 trace_len = (hbh1->length + 1) << 3;
2594 t->next_index = next1;
2595 /* Capture the h-b-h option verbatim */
2596 trace_len =
2597 trace_len <
2598 ARRAY_LEN (t->option_data) ? trace_len :
2599 ARRAY_LEN (t->option_data);
2600 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002601 clib_memcpy_fast (t->option_data, hbh1, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002602 }
2603
2604 }
2605
2606 b0->error = error_node->errors[error0];
2607 b1->error = error_node->errors[error1];
2608
2609 /* verify speculative enqueue, maybe switch current next frame */
2610 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2611 n_left_to_next, bi0, bi1, next0,
2612 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002613 }
2614
Dave Barachd7cb1b52016-12-09 09:52:16 -05002615 while (n_left_from > 0 && n_left_to_next > 0)
2616 {
2617 u32 bi0;
2618 vlib_buffer_t *b0;
2619 u32 next0;
2620 ip6_header_t *ip0;
2621 ip6_hop_by_hop_header_t *hbh0;
2622 ip6_hop_by_hop_option_t *opt0, *limit0;
2623 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002624
Dave Barachd7cb1b52016-12-09 09:52:16 -05002625 /* Speculatively enqueue b0 to the current next frame */
2626 bi0 = from[0];
2627 to_next[0] = bi0;
2628 from += 1;
2629 to_next += 1;
2630 n_left_from -= 1;
2631 n_left_to_next -= 1;
2632
2633 b0 = vlib_get_buffer (vm, bi0);
2634 /*
2635 * Default use the next_index from the adjacency.
2636 * A HBH option rarely redirects to a different node
2637 */
2638 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002639 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002640 next0 = adj0->lookup_next_index;
2641
2642 ip0 = vlib_buffer_get_current (b0);
2643 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2644 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2645 limit0 =
2646 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2647 ((hbh0->length + 1) << 3));
2648
2649 /*
2650 * Basic validity checks
2651 */
2652 if ((hbh0->length + 1) << 3 >
2653 clib_net_to_host_u16 (ip0->payload_length))
2654 {
2655 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2656 next0 = IP_LOOKUP_NEXT_DROP;
2657 goto out0;
2658 }
2659
2660 /* Scan the set of h-b-h options, process ones that we understand */
2661 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2662
2663 out0:
2664 /* Has the classifier flagged this buffer for special treatment? */
2665 if (PREDICT_FALSE
2666 ((error0 == 0)
2667 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2668 next0 = hm->next_override;
2669
2670 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2671 {
2672 ip6_hop_by_hop_trace_t *t =
2673 vlib_add_trace (vm, node, b0, sizeof (*t));
2674 u32 trace_len = (hbh0->length + 1) << 3;
2675 t->next_index = next0;
2676 /* Capture the h-b-h option verbatim */
2677 trace_len =
2678 trace_len <
2679 ARRAY_LEN (t->option_data) ? trace_len :
2680 ARRAY_LEN (t->option_data);
2681 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002682 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683 }
2684
2685 b0->error = error_node->errors[error0];
2686
2687 /* verify speculative enqueue, maybe switch current next frame */
2688 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2689 n_left_to_next, bi0, next0);
2690 }
2691 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002692 }
Ole Troan944f5482016-05-24 11:56:58 +02002693 return frame->n_vectors;
2694}
2695
Dave Barachd7cb1b52016-12-09 09:52:16 -05002696/* *INDENT-OFF* */
2697VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2698{
Ole Troan944f5482016-05-24 11:56:58 +02002699 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002700 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002701 .vector_size = sizeof (u32),
2702 .format_trace = format_ip6_hop_by_hop_trace,
2703 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002704 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002705 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002706 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002707};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002708/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002709
Ole Troan944f5482016-05-24 11:56:58 +02002710static clib_error_t *
2711ip6_hop_by_hop_init (vlib_main_t * vm)
2712{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002713 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Dave Barachb7b92992018-10-17 10:38:51 -04002714 clib_memset (hm->options, 0, sizeof (hm->options));
2715 clib_memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002716 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002717 return (0);
2718}
2719
2720VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2721
Damjan Marion38173502019-02-13 19:30:09 +01002722#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723void
2724ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002725{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002726 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002727
2728 hm->next_override = next;
2729}
2730
Ole Troan944f5482016-05-24 11:56:58 +02002731int
2732ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002733 int options (vlib_buffer_t * b, ip6_header_t * ip,
2734 ip6_hop_by_hop_option_t * opt),
2735 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002736{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002737 ip6_main_t *im = &ip6_main;
2738 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002739
Neale Ranns756cd942018-04-06 09:18:11 -07002740 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002741
2742 /* Already registered */
2743 if (hm->options[option])
2744 return (-1);
2745
2746 hm->options[option] = options;
2747 hm->trace[option] = trace;
2748
2749 /* Set global variable */
2750 im->hbh_enabled = 1;
2751
2752 return (0);
2753}
2754
2755int
2756ip6_hbh_unregister_option (u8 option)
2757{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002758 ip6_main_t *im = &ip6_main;
2759 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002760
Neale Ranns756cd942018-04-06 09:18:11 -07002761 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002762
2763 /* Not registered */
2764 if (!hm->options[option])
2765 return (-1);
2766
2767 hm->options[option] = NULL;
2768 hm->trace[option] = NULL;
2769
2770 /* Disable global knob if this was the last option configured */
2771 int i;
2772 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002773 for (i = 0; i < 256; i++)
2774 {
2775 if (hm->options[option])
2776 {
2777 found = true;
2778 break;
2779 }
Ole Troan944f5482016-05-24 11:56:58 +02002780 }
Ole Troan944f5482016-05-24 11:56:58 +02002781 if (!found)
2782 im->hbh_enabled = 0;
2783
2784 return (0);
2785}
2786
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787/* Global IP6 main. */
2788ip6_main_t ip6_main;
Damjan Marion38173502019-02-13 19:30:09 +01002789#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002790
2791static clib_error_t *
2792ip6_lookup_init (vlib_main_t * vm)
2793{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002794 ip6_main_t *im = &ip6_main;
2795 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002796 uword i;
2797
Damjan Marion8b3191e2016-11-09 19:54:20 +01002798 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2799 return error;
2800
Ed Warnickecb9cada2015-12-08 15:45:58 -07002801 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2802 {
2803 u32 j, i0, i1;
2804
2805 i0 = i / 32;
2806 i1 = i % 32;
2807
2808 for (j = 0; j < i0; j++)
2809 im->fib_masks[i].as_u32[j] = ~0;
2810
2811 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002812 im->fib_masks[i].as_u32[i0] =
2813 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002814 }
2815
2816 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2817
Ed Warnickecb9cada2015-12-08 15:45:58 -07002818 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07002819 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2820 FIB_SOURCE_DEFAULT_ROUTE);
2821 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2822 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823
2824 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002825 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002826 pn = pg_get_node (ip6_lookup_node.index);
2827 pn->unformat_edit = unformat_pg_ip6_header;
2828 }
2829
Ole Troan944f5482016-05-24 11:56:58 +02002830 /* Unless explicitly configured, don't process HBH options */
2831 im->hbh_enabled = 0;
2832
Dave Barach203c6322016-06-26 10:29:03 -04002833 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002834}
2835
2836VLIB_INIT_FUNCTION (ip6_lookup_init);
2837
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838static clib_error_t *
2839set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002840 unformat_input_t * input,
2841 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842{
2843 int matched = 0;
2844 u32 table_id = 0;
2845 u32 flow_hash_config = 0;
2846 int rv;
2847
Dave Barachd7cb1b52016-12-09 09:52:16 -05002848 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2849 {
2850 if (unformat (input, "table %d", &table_id))
2851 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002852#define _(a, b, v) \
2853 else if (unformat (input, #a)) \
2854 { \
2855 flow_hash_config |= v; \
2856 matched = 1; \
2857 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002858 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002859#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860 else
2861 break;
2862 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002863
2864 if (matched == 0)
2865 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002866 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002867
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002868 rv = ip_flow_hash_set (AF_IP6, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002869 switch (rv)
2870 {
Neale Ranns227038a2017-04-21 01:07:59 -07002871 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002872 break;
2873
2874 case -1:
2875 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002876
Ed Warnickecb9cada2015-12-08 15:45:58 -07002877 default:
2878 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2879 break;
2880 }
Dave Barach75fc8542016-10-11 16:16:02 -04002881
Ed Warnickecb9cada2015-12-08 15:45:58 -07002882 return 0;
2883}
2884
Billy McFall0683c9c2016-10-13 08:27:31 -04002885/*?
2886 * Configure the set of IPv6 fields used by the flow hash.
2887 *
2888 * @cliexpar
2889 * @parblock
2890 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04002891 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2892 *
Billy McFall0683c9c2016-10-13 08:27:31 -04002893 * Example of display the configured flow hash:
2894 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002895 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2896 * @::/0
2897 * unicast-ip6-chain
2898 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2899 * [0] [@0]: dpo-drop ip6
2900 * fe80::/10
2901 * unicast-ip6-chain
2902 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2903 * [0] [@2]: dpo-receive
2904 * ff02::1/128
2905 * unicast-ip6-chain
2906 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2907 * [0] [@2]: dpo-receive
2908 * ff02::2/128
2909 * unicast-ip6-chain
2910 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2911 * [0] [@2]: dpo-receive
2912 * ff02::16/128
2913 * unicast-ip6-chain
2914 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2915 * [0] [@2]: dpo-receive
2916 * ff02::1:ff00:0/104
2917 * unicast-ip6-chain
2918 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2919 * [0] [@2]: dpo-receive
2920 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2921 * @::/0
2922 * unicast-ip6-chain
2923 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2924 * [0] [@0]: dpo-drop ip6
2925 * @::a:1:1:0:4/126
2926 * unicast-ip6-chain
2927 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2928 * [0] [@4]: ipv6-glean: af_packet0
2929 * @::a:1:1:0:7/128
2930 * unicast-ip6-chain
2931 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2932 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2933 * fe80::/10
2934 * unicast-ip6-chain
2935 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2936 * [0] [@2]: dpo-receive
2937 * fe80::fe:3eff:fe3e:9222/128
2938 * unicast-ip6-chain
2939 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2940 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2941 * ff02::1/128
2942 * unicast-ip6-chain
2943 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2944 * [0] [@2]: dpo-receive
2945 * ff02::2/128
2946 * unicast-ip6-chain
2947 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2948 * [0] [@2]: dpo-receive
2949 * ff02::16/128
2950 * unicast-ip6-chain
2951 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2952 * [0] [@2]: dpo-receive
2953 * ff02::1:ff00:0/104
2954 * unicast-ip6-chain
2955 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2956 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04002957 * @cliexend
2958 * @endparblock
2959?*/
2960/* *INDENT-OFF* */
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002961VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962 .path = "set ip6 flow-hash",
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002963 .short_help = "set ip6 flow-hash table <table-id> [src] [dst] [sport] "
2964 "[dport] [proto] [reverse] [flowlabel]",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002965 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002966};
Billy McFall0683c9c2016-10-13 08:27:31 -04002967/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968
2969static clib_error_t *
2970show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002971 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002973 ip6_main_t *im = &ip6_main;
2974 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002975 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04002976
Ed Warnickecb9cada2015-12-08 15:45:58 -07002977 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05002978 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002979 {
2980 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02002981 {
2982
2983 u32 node_index = vlib_get_node (vm,
2984 ip6_local_node.index)->
2985 next_nodes[lm->local_next_by_ip_protocol[i]];
2986 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2987 node_index);
2988 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002989 }
2990 return 0;
2991}
2992
2993
2994
Billy McFall0683c9c2016-10-13 08:27:31 -04002995/*?
2996 * Display the set of protocols handled by the local IPv6 stack.
2997 *
2998 * @cliexpar
2999 * Example of how to display local protocol table:
3000 * @cliexstart{show ip6 local}
3001 * Protocols handled by ip6_local
3002 * 17
3003 * 43
3004 * 58
3005 * 115
3006 * @cliexend
3007?*/
3008/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003009VLIB_CLI_COMMAND (show_ip6_local, static) =
3010{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003011 .path = "show ip6 local",
3012 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003013 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014};
Billy McFall0683c9c2016-10-13 08:27:31 -04003015/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016
Damjan Marion38173502019-02-13 19:30:09 +01003017#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003018int
Mohsin Kazmi68095382021-02-10 11:26:24 +01003019vnet_set_ip6_classify_intfc (vlib_main_t *vm, u32 sw_if_index, u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003020{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021 vnet_main_t *vnm = vnet_get_main ();
3022 vnet_interface_main_t *im = &vnm->interface_main;
3023 ip6_main_t *ipm = &ip6_main;
3024 ip_lookup_main_t *lm = &ipm->lookup_main;
3025 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003026 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003027
3028 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3029 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3030
3031 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3032 return VNET_API_ERROR_NO_SUCH_ENTRY;
3033
3034 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003035 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003037 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003038
3039 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003040 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003041 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003042 .fp_len = 128,
3043 .fp_proto = FIB_PROTOCOL_IP6,
3044 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003045 };
3046 u32 fib_index;
3047
Dave Barachd7cb1b52016-12-09 09:52:16 -05003048 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3049 sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003050 if (table_index != (u32) ~ 0)
3051 {
3052 dpo_id_t dpo = DPO_INVALID;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003053 dpo_set (&dpo,
3054 DPO_CLASSIFY,
3055 DPO_PROTO_IP6,
3056 classify_dpo_create (DPO_PROTO_IP6, table_index));
Dave Barachd7cb1b52016-12-09 09:52:16 -05003057 fib_table_entry_special_dpo_add (fib_index,
3058 &pfx,
3059 FIB_SOURCE_CLASSIFY,
3060 FIB_ENTRY_FLAG_NONE, &dpo);
3061 dpo_reset (&dpo);
3062 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003063 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064 {
3065 fib_table_entry_special_remove (fib_index,
3066 &pfx, FIB_SOURCE_CLASSIFY);
3067 }
3068 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003069
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070 return 0;
3071}
Damjan Marion38173502019-02-13 19:30:09 +01003072#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003073
3074static clib_error_t *
3075set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003076 unformat_input_t * input,
3077 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003078{
3079 u32 table_index = ~0;
3080 int table_index_set = 0;
3081 u32 sw_if_index = ~0;
3082 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003083
Dave Barachd7cb1b52016-12-09 09:52:16 -05003084 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3085 {
3086 if (unformat (input, "table-index %d", &table_index))
3087 table_index_set = 1;
3088 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3089 vnet_get_main (), &sw_if_index))
3090 ;
3091 else
3092 break;
3093 }
Dave Barach75fc8542016-10-11 16:16:02 -04003094
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003096 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003097
Ed Warnickecb9cada2015-12-08 15:45:58 -07003098 if (sw_if_index == ~0)
3099 return clib_error_return (0, "interface / subif must be specified");
3100
3101 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3102
3103 switch (rv)
3104 {
3105 case 0:
3106 break;
3107
3108 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3109 return clib_error_return (0, "No such interface");
3110
3111 case VNET_API_ERROR_NO_SUCH_ENTRY:
3112 return clib_error_return (0, "No such classifier table");
3113 }
3114 return 0;
3115}
3116
Billy McFall0683c9c2016-10-13 08:27:31 -04003117/*?
3118 * Assign a classification table to an interface. The classification
3119 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3120 * commands. Once the table is create, use this command to filter packets
3121 * on an interface.
3122 *
3123 * @cliexpar
3124 * Example of how to assign a classification table to an interface:
3125 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3126?*/
3127/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003128VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3129{
3130 .path = "set ip6 classify",
3131 .short_help =
3132 "set ip6 classify intfc <interface> table-index <classify-idx>",
3133 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134};
Billy McFall0683c9c2016-10-13 08:27:31 -04003135/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003136
Dave Barachd7cb1b52016-12-09 09:52:16 -05003137/*
3138 * fd.io coding-style-patch-verification: ON
3139 *
3140 * Local Variables:
3141 * eval: (c-set-style "gnu")
3142 * End:
3143 */