blob: 8daf2614c1508eaca496cd018e72bcf7e98eb8d4 [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)
313 return error;
Pavel Kotucek57808982017-08-02 08:20:19 +0200314
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200315 if (ip6_address_is_link_local_unicast (address))
316 {
317 if (address_length != 128)
318 {
319 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
320 return
321 clib_error_create
322 ("prefix length of link-local address must be 128");
323 }
324 if (!is_del)
325 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000326 int rv;
327
Neale Rannsec40a7d2020-04-23 07:36:12 +0000328 rv = ip6_link_set_local_address (sw_if_index, address);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000329
330 if (rv)
331 {
332 vnm->api_errno = rv;
333 return clib_error_create ("address not assignable");
334 }
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200335 }
336 else
337 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000338 ll_addr = ip6_get_link_local_address (sw_if_index);
339 if (ip6_address_is_equal (ll_addr, address))
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200340 {
341 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
342 return clib_error_create ("address not deletable");
343 }
344 else
345 {
346 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
347 return clib_error_create ("address not found");
348 }
349 }
Neale Rannsec40a7d2020-04-23 07:36:12 +0000350
351 return (NULL);
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200352 }
353
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354 ip6_addr_fib_init (&ip6_af, address,
355 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
356 vec_add1 (addr_fib, ip6_af);
357
Neale Ranns744902e2017-08-14 10:35:44 -0700358 /* *INDENT-OFF* */
359 if (!is_del)
360 {
361 /* When adding an address check that it does not conflict
362 with an existing address on any interface in this table. */
363 ip_interface_address_t *ia;
364 vnet_sw_interface_t *sif;
365
Damjan Marionb2c31b62020-12-13 21:47:40 +0100366 pool_foreach (sif, vnm->interface_main.sw_interfaces)
367 {
Neale Ranns744902e2017-08-14 10:35:44 -0700368 if (im->fib_index_by_sw_if_index[sw_if_index] ==
369 im->fib_index_by_sw_if_index[sif->sw_if_index])
370 {
371 foreach_ip_interface_address
372 (&im->lookup_main, ia, sif->sw_if_index,
373 0 /* honor unnumbered */ ,
374 ({
375 ip6_address_t * x =
376 ip_interface_address_get_address
377 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000378
Neale Ranns744902e2017-08-14 10:35:44 -0700379 if (ip6_destination_matches_route
380 (im, address, x, ia->address_length) ||
381 ip6_destination_matches_route (im,
382 x,
383 address,
384 address_length))
385 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500386 /* an intf may have >1 addr from the same prefix */
387 if ((sw_if_index == sif->sw_if_index) &&
388 (ia->address_length == address_length) &&
389 !ip6_address_is_equal (x, address))
390 continue;
391
Neale Ranns59f71132020-04-08 12:19:38 +0000392 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
393 /* if the address we're comparing against is stale
394 * then the CP has not added this one back yet, maybe
395 * it never will, so we have to assume it won't and
396 * ignore it. if it does add it back, then it will fail
397 * because this one is now present */
398 continue;
399
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500400 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700401 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
Neale Ranns59f71132020-04-08 12:19:38 +0000402 error = clib_error_create
Neale Ranns744902e2017-08-14 10:35:44 -0700403 ("failed to add %U which conflicts with %U for interface %U",
404 format_ip6_address_and_length, address,
405 address_length,
406 format_ip6_address_and_length, x,
407 ia->address_length,
408 format_vnet_sw_if_index_name, vnm,
409 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000410 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700411 }
412 }));
413 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100414 }
Neale Ranns744902e2017-08-14 10:35:44 -0700415 }
416 /* *INDENT-ON* */
417
Neale Ranns59f71132020-04-08 12:19:38 +0000418 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419
Neale Ranns59f71132020-04-08 12:19:38 +0000420 if (is_del)
421 {
422 if (~0 == if_address_index)
423 {
424 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
425 error = clib_error_create ("%U not found for interface %U",
426 lm->format_address_and_length,
427 addr_fib, address_length,
428 format_vnet_sw_if_index_name, vnm,
429 sw_if_index);
430 goto done;
431 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432
yedgdbd366b2020-05-14 10:51:53 +0800433 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
434 address_length, sw_if_index);
435 if (error)
436 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000437 }
438 else
439 {
440 if (~0 != if_address_index)
441 {
442 ip_interface_address_t *ia;
443
444 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
445
446 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
447 {
448 if (ia->sw_if_index == sw_if_index)
449 {
450 /* re-adding an address during the replace action.
451 * consdier this the update. clear the flag and
452 * we're done */
453 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
454 goto done;
455 }
456 else
457 {
458 /* The prefix is moving from one interface to another.
459 * delete the stale and add the new */
460 ip6_add_del_interface_address (vm,
461 ia->sw_if_index,
462 address, address_length, 1);
463 ia = NULL;
464 error = ip_interface_address_add (lm, sw_if_index,
465 addr_fib, address_length,
466 &if_address_index);
467 }
468 }
469 else
470 {
471 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
472 error = clib_error_create
473 ("Prefix %U already found on interface %U",
474 lm->format_address_and_length, addr_fib, address_length,
475 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
476 }
477 }
478 else
479 error = ip_interface_address_add (lm, sw_if_index,
480 addr_fib, address_length,
481 &if_address_index);
482 }
483
484 if (error)
485 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486
Dave Barachd7cb1b52016-12-09 09:52:16 -0500487 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000488 if (!is_del)
Neale Rannsec40a7d2020-04-23 07:36:12 +0000489 ip6_link_enable (sw_if_index, NULL);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000490
Neale Ranns1ff3c152019-10-07 22:40:54 -0700491 /* intf addr routes are added/deleted on admin up/down */
492 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
493 {
494 if (is_del)
495 ip6_del_interface_routes (sw_if_index,
496 im, ip6_af.fib_index, address,
497 address_length);
498 else
499 ip6_add_interface_routes (vnm, sw_if_index,
500 im, ip6_af.fib_index,
501 pool_elt_at_index (lm->if_address_pool,
502 if_address_index));
503 }
Neale Ranns59f71132020-04-08 12:19:38 +0000504
505 ip6_add_del_interface_address_callback_t *cb;
506 vec_foreach (cb, im->add_del_interface_address_callbacks)
507 cb->function (im, cb->function_opaque, sw_if_index,
508 address, address_length, if_address_index, is_del);
509
Neale Rannscbe25aa2019-09-30 10:53:31 +0000510 if (is_del)
511 ip6_link_disable (sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512
Dave Barachd7cb1b52016-12-09 09:52:16 -0500513done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700514 vec_free (addr_fib);
515 return error;
516}
517
Damjan Marion38173502019-02-13 19:30:09 +0100518#endif
519
520static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500521ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523 ip6_main_t *im = &ip6_main;
524 ip_interface_address_t *ia;
525 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 u32 is_admin_up, fib_index;
527
Dave Barachd7cb1b52016-12-09 09:52:16 -0500528 vec_validate_init_empty (im->
529 lookup_main.if_address_pool_index_by_sw_if_index,
530 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700531
532 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
533
534 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
535
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400537 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700538 0 /* honor unnumbered */,
539 ({
540 a = ip_interface_address_get_address (&im->lookup_main, ia);
541 if (is_admin_up)
542 ip6_add_interface_routes (vnm, sw_if_index,
543 im, fib_index,
544 ia);
545 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500546 ip6_del_interface_routes (sw_if_index, im, fib_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 a, ia->address_length);
548 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500549 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550
551 return 0;
552}
553
554VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
555
Dave Barachd6534602016-06-14 18:38:02 -0400556/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500557/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100558VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
559{
560 .arc_name = "ip6-unicast",
561 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500562 .last_in_arc = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100563 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
564};
565
Dave Barachd7cb1b52016-12-09 09:52:16 -0500566VNET_FEATURE_INIT (ip6_flow_classify, static) =
567{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100568 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700569 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100570 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700571};
572
Dave Barachd7cb1b52016-12-09 09:52:16 -0500573VNET_FEATURE_INIT (ip6_inacl, static) =
574{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100575 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400576 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100577 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400578};
579
Dave Barachd7cb1b52016-12-09 09:52:16 -0500580VNET_FEATURE_INIT (ip6_policer_classify, static) =
581{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100582 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700583 .node_name = "ip6-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100584 .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700585};
586
Dave Barachd7cb1b52016-12-09 09:52:16 -0500587VNET_FEATURE_INIT (ip6_ipsec, static) =
588{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100589 .arc_name = "ip6-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100590 .node_name = "ipsec6-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100591 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400592};
593
Dave Barachd7cb1b52016-12-09 09:52:16 -0500594VNET_FEATURE_INIT (ip6_l2tp, static) =
595{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100596 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400597 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100598 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400599};
600
Dave Barachd7cb1b52016-12-09 09:52:16 -0500601VNET_FEATURE_INIT (ip6_vpath, static) =
602{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100603 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400604 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500605 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
606};
607
608VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
609{
610 .arc_name = "ip6-unicast",
611 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100612 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400613};
614
Neale Ranns8269d3d2018-01-30 09:02:20 -0800615VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100617 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800618 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400619 .runs_before = VNET_FEATURES ("ip6-lookup"),
620};
621
622VNET_FEATURE_INIT (ip6_lookup, static) =
623{
624 .arc_name = "ip6-unicast",
625 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100626 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100627};
628
Dave Barachd6534602016-06-14 18:38:02 -0400629/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100630VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
631{
632 .arc_name = "ip6-multicast",
633 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500634 .last_in_arc = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100635 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
636};
637
638VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
639 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400640 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000641 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400642};
643
Neale Ranns8269d3d2018-01-30 09:02:20 -0800644VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100645 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800646 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400647 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
648};
649
650VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
651 .arc_name = "ip6-multicast",
652 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100653 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100654};
Dave Barach5331c722016-08-17 11:54:30 -0400655
656/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100657VNET_FEATURE_ARC_INIT (ip6_output, static) =
658{
659 .arc_name = "ip6-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800660 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500661 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100662 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400663};
664
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100665VNET_FEATURE_INIT (ip6_outacl, static) = {
666 .arc_name = "ip6-output",
667 .node_name = "ip6-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100668 .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100669};
670
Matus Fabian08a6f012016-11-15 06:08:51 -0800671VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
672 .arc_name = "ip6-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100673 .node_name = "ipsec6-output-feature",
Matus Fabian08a6f012016-11-15 06:08:51 -0800674 .runs_before = VNET_FEATURES ("interface-output"),
675};
676
Damjan Marion8b3191e2016-11-09 19:54:20 +0100677VNET_FEATURE_INIT (ip6_interface_output, static) = {
678 .arc_name = "ip6-output",
679 .node_name = "interface-output",
680 .runs_before = 0, /* not before any other features */
681};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500682/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400683
Damjan Marion38173502019-02-13 19:30:09 +0100684static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500685ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700687 ip6_main_t *im = &ip6_main;
688
Nathan Skrzypczak7854b462021-08-16 16:13:40 +0200689 vec_validate_init_empty (im->fib_index_by_sw_if_index, sw_if_index, ~0);
690 vec_validate_init_empty (im->mfib_index_by_sw_if_index, sw_if_index, ~0);
Florin Corasb5c13fd2017-05-10 12:32:53 -0700691
Nathan Skrzypczak7854b462021-08-16 16:13:40 +0200692 if (is_add)
693 {
694 /* Fill in lookup tables with default table (0). */
695 im->fib_index_by_sw_if_index[sw_if_index] = 0;
696 im->mfib_index_by_sw_if_index[sw_if_index] = 0;
697 }
698 else
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200699 {
700 /* Ensure that IPv6 is disabled */
701 ip6_main_t *im6 = &ip6_main;
702 ip_lookup_main_t *lm6 = &im6->lookup_main;
703 ip_interface_address_t *ia = 0;
704 ip6_address_t *address;
705 vlib_main_t *vm = vlib_get_main ();
706
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700707 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200708 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700709 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200710 ({
711 address = ip_interface_address_get_address (lm6, ia);
712 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
713 }));
714 /* *INDENT-ON* */
715 ip6_mfib_interface_enable_disable (sw_if_index, 0);
716 }
717
Neale Ranns8269d3d2018-01-30 09:02:20 -0800718 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100719 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720
Neale Ranns8269d3d2018-01-30 09:02:20 -0800721 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
722 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724 return /* no error */ 0;
725}
726
727VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
728
Damjan Marion38173502019-02-13 19:30:09 +0100729VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
730 vlib_node_runtime_t * node,
731 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200732{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100733 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200734}
735
Dave Barachd7cb1b52016-12-09 09:52:16 -0500736static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100737
Dave Barachd7cb1b52016-12-09 09:52:16 -0500738/* *INDENT-OFF* */
739VLIB_REGISTER_NODE (ip6_lookup_node) =
740{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741 .name = "ip6-lookup",
742 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100743 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200744 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200745 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500747/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748
Damjan Marion38173502019-02-13 19:30:09 +0100749VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
750 vlib_node_runtime_t * node,
751 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200752{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500753 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400754 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200755 u32 thread_index = vm->thread_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 ip6_main_t *im = &ip6_main;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400757 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
758 u16 nexts[VLIB_FRAME_SIZE], *next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759
760 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400761 n_left = frame->n_vectors;
762 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100763
Neale Ranns3ce72b22019-05-27 08:21:32 -0400764 vlib_get_buffers (vm, from, bufs, n_left);
765
766 while (n_left >= 4)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100767 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400768 const load_balance_t *lb0, *lb1;
769 const ip6_header_t *ip0, *ip1;
770 u32 lbi0, hc0, lbi1, hc1;
771 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100772
Neale Ranns3ce72b22019-05-27 08:21:32 -0400773 /* Prefetch next iteration. */
774 {
775 vlib_prefetch_buffer_header (b[2], STORE);
776 vlib_prefetch_buffer_header (b[3], STORE);
Dave Barach75fc8542016-10-11 16:16:02 -0400777
Neale Ranns3ce72b22019-05-27 08:21:32 -0400778 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
779 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
780 }
781
782 ip0 = vlib_buffer_get_current (b[0]);
783 ip1 = vlib_buffer_get_current (b[1]);
784 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
785 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
786
787 lb0 = load_balance_get (lbi0);
788 lb1 = load_balance_get (lbi1);
789
790 /*
791 * this node is for via FIBs we can re-use the hash value from the
792 * to node if present.
793 * We don't want to use the same hash value at each level in the recursion
794 * graph as that would lead to polarisation
795 */
796 hc0 = hc1 = 0;
797
798 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500799 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400800 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400802 hc0 = vnet_buffer (b[0])->ip.flow_hash =
803 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700804 }
805 else
806 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400807 hc0 = vnet_buffer (b[0])->ip.flow_hash =
808 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400810 dpo0 = load_balance_get_fwd_bucket
811 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
812 }
813 else
814 {
815 dpo0 = load_balance_get_bucket_i (lb0, 0);
816 }
817 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
818 {
819 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500820 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400821 hc1 = vnet_buffer (b[1])->ip.flow_hash =
822 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700824 else
825 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400826 hc1 = vnet_buffer (b[1])->ip.flow_hash =
827 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700828 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400829 dpo1 = load_balance_get_fwd_bucket
830 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
831 }
832 else
833 {
834 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500835 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000836
Neale Ranns3ce72b22019-05-27 08:21:32 -0400837 next[0] = dpo0->dpoi_next_node;
838 next[1] = dpo1->dpoi_next_node;
839
840 /* Only process the HBH Option Header if explicitly configured to do so */
841 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500842 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400843 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
844 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
845 }
846 /* Only process the HBH Option Header if explicitly configured to do so */
847 if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
848 {
849 next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
850 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500851 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100852
Neale Ranns3ce72b22019-05-27 08:21:32 -0400853 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
854 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
855
856 vlib_increment_combined_counter
857 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
858 vlib_increment_combined_counter
859 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
860
861 b += 2;
862 next += 2;
863 n_left -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100864 }
865
Neale Ranns3ce72b22019-05-27 08:21:32 -0400866 while (n_left > 0)
867 {
868 const load_balance_t *lb0;
869 const ip6_header_t *ip0;
870 const dpo_id_t *dpo0;
871 u32 lbi0, hc0;
872
873 ip0 = vlib_buffer_get_current (b[0]);
874 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
875
876 lb0 = load_balance_get (lbi0);
877
878 hc0 = 0;
879 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
880 {
881 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
882 {
883 hc0 = vnet_buffer (b[0])->ip.flow_hash =
884 vnet_buffer (b[0])->ip.flow_hash >> 1;
885 }
886 else
887 {
888 hc0 = vnet_buffer (b[0])->ip.flow_hash =
889 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
890 }
891 dpo0 = load_balance_get_fwd_bucket
892 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
893 }
894 else
895 {
896 dpo0 = load_balance_get_bucket_i (lb0, 0);
897 }
898
899 next[0] = dpo0->dpoi_next_node;
900 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
901
902 /* Only process the HBH Option Header if explicitly configured to do so */
903 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
904 {
905 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
906 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
907 }
908
909 vlib_increment_combined_counter
910 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
911
912 b += 1;
913 next += 1;
914 n_left -= 1;
915 }
916
917 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
918
Neale Rannsa71844f2018-11-08 07:31:36 -0800919 if (node->flags & VLIB_NODE_FLAG_TRACE)
920 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
921
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100922 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200923}
924
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925/* *INDENT-OFF* */
926VLIB_REGISTER_NODE (ip6_load_balance_node) =
927{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100928 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200929 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200930 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100931 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200932};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500933/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200934
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935typedef struct
936{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937 /* Adjacency taken. */
938 u32 adj_index;
939 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500940 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941
942 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500943 u8 packet_data[128 - 1 * sizeof (u32)];
944}
945ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946
Damjan Marion38173502019-02-13 19:30:09 +0100947#ifndef CLIB_MARCH_VARIANT
John Lo2b81eb82017-01-30 13:12:10 -0500948u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500949format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700950{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100951 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
952 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500953 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200954 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100955
Neale Rannsdc617b82020-08-20 08:22:56 +0000956 s = format (s, "%Ufib:%d adj:%d flow:%d",
957 format_white_space, indent,
958 t->fib_index, t->adj_index, t->flow_hash);
959 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960 format_white_space, indent,
961 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100962 return s;
963}
Damjan Marion38173502019-02-13 19:30:09 +0100964#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100965
Dave Barachd7cb1b52016-12-09 09:52:16 -0500966static u8 *
967format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100968{
969 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
970 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500971 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200972 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973
John Loac8146c2016-09-27 17:44:02 -0400974 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975 t->fib_index, t->adj_index, t->flow_hash);
976 s = format (s, "\n%U%U",
977 format_white_space, indent,
978 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100979 return s;
980}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100981
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983static u8 *
984format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100985{
986 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
987 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500988 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200989 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100991 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500992 t->fib_index, t->adj_index, format_ip_adjacency,
993 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100994 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 format_white_space, indent,
996 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +0000997 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998 return s;
999}
1000
1001/* Common trace function for all ip6-forward next nodes. */
Damjan Marion38173502019-02-13 19:30:09 +01001002#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003void
1004ip6_forward_next_trace (vlib_main_t * vm,
1005 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001006 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001008 u32 *from, n_left;
1009 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010
1011 n_left = frame->n_vectors;
1012 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001013
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014 while (n_left >= 4)
1015 {
1016 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001017 vlib_buffer_t *b0, *b1;
1018 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001019
1020 /* Prefetch next iteration. */
1021 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1022 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1023
1024 bi0 = from[0];
1025 bi1 = from[1];
1026
1027 b0 = vlib_get_buffer (vm, bi0);
1028 b1 = vlib_get_buffer (vm, bi1);
1029
1030 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1031 {
1032 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1033 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001034 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1035 t0->fib_index =
1036 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1037 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1038 vec_elt (im->fib_index_by_sw_if_index,
1039 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001040
Dave Barach178cf492018-11-13 16:34:13 -05001041 clib_memcpy_fast (t0->packet_data,
1042 vlib_buffer_get_current (b0),
1043 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044 }
1045 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1046 {
1047 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1048 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001049 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1050 t1->fib_index =
1051 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1052 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1053 vec_elt (im->fib_index_by_sw_if_index,
1054 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001055
Dave Barach178cf492018-11-13 16:34:13 -05001056 clib_memcpy_fast (t1->packet_data,
1057 vlib_buffer_get_current (b1),
1058 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001059 }
1060 from += 2;
1061 n_left -= 2;
1062 }
1063
1064 while (n_left >= 1)
1065 {
1066 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001067 vlib_buffer_t *b0;
1068 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069
1070 bi0 = from[0];
1071
1072 b0 = vlib_get_buffer (vm, bi0);
1073
1074 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1075 {
1076 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1077 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001078 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1079 t0->fib_index =
1080 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1081 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1082 vec_elt (im->fib_index_by_sw_if_index,
1083 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001084
Dave Barach178cf492018-11-13 16:34:13 -05001085 clib_memcpy_fast (t0->packet_data,
1086 vlib_buffer_get_current (b0),
1087 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088 }
1089 from += 1;
1090 n_left -= 1;
1091 }
1092}
1093
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001095u16
1096ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1097 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098{
Matthew Smith97677a22020-02-05 11:46:40 -06001099 ip_csum_t sum0 = 0;
1100 u16 payload_length, payload_length_host_byte_order;
Srikanth A02833ff2019-10-02 17:48:58 -07001101 u32 i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001102 u32 headers_size = sizeof (ip0[0]);
Dave Barachc4abafd2019-09-04 12:09:32 -04001103 u8 *data_this_buffer;
Matthew Smith97677a22020-02-05 11:46:40 -06001104 u8 next_hdr = ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
Dave Barachd7cb1b52016-12-09 09:52:16 -05001106 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107 *bogus_lengthp = 0;
1108
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
Dave Barachc4abafd2019-09-04 12:09:32 -04001110 data_this_buffer = (u8 *) (ip0 + 1);
Matthew Smith97677a22020-02-05 11:46:40 -06001111 payload_length = ip0->payload_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301113 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1114 * or UDP-Ping packets */
Matthew Smith97677a22020-02-05 11:46:40 -06001115 if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001117 u32 skip_bytes;
1118 ip6_hop_by_hop_ext_t *ext_hdr =
1119 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
1121 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301122 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1123 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124
Dave Barachd7cb1b52016-12-09 09:52:16 -05001125 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1126 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001127
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 headers_size += skip_bytes;
Matthew Smith97677a22020-02-05 11:46:40 -06001130
1131 /* pseudo-header adjustments:
1132 * exclude ext header bytes from payload length
1133 * use payload IP proto rather than ext header IP proto
1134 */
1135 payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1136 next_hdr = ext_hdr->next_hdr;
1137 }
1138
1139 /* Initialize checksum with ip pseudo-header. */
1140 sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1141
1142 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1143 {
1144 sum0 = ip_csum_with_carry
1145 (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1146 sum0 = ip_csum_with_carry
1147 (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149
John Lo3bc6bc22019-08-03 14:36:39 -04001150 if (p0)
Srikanth A02833ff2019-10-02 17:48:58 -07001151 return ip_calculate_l4_checksum (vm, p0, sum0,
1152 payload_length_host_byte_order,
1153 (u8 *) ip0, headers_size, NULL);
1154 else
1155 return ip_calculate_l4_checksum (vm, 0, sum0,
1156 payload_length_host_byte_order, NULL, 0,
1157 data_this_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158}
1159
Dave Barachd7cb1b52016-12-09 09:52:16 -05001160u32
1161ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1164 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 u16 sum16;
1166 int bogus_length;
1167
1168 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1169 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1170 || ip0->protocol == IP_PROTOCOL_ICMP6
1171 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001172 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
1174 udp0 = (void *) (ip0 + 1);
1175 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1176 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001177 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1178 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 return p0->flags;
1180 }
1181
1182 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1183
Damjan Marion213b5aa2017-07-13 21:19:27 +02001184 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1185 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186
1187 return p0->flags;
1188}
Damjan Marion38173502019-02-13 19:30:09 +01001189#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301191/**
1192 * @brief returns number of links on which src is reachable.
1193 */
1194always_inline int
1195ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1196{
1197 const load_balance_t *lb0;
1198 index_t lbi;
Florin Corasf3a3bad2018-03-28 02:18:29 -07001199 u32 fib_index;
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301200
Florin Corasf3a3bad2018-03-28 02:18:29 -07001201 fib_index = vec_elt (im->fib_index_by_sw_if_index,
1202 vnet_buffer (b)->sw_if_index[VLIB_RX]);
1203 fib_index =
1204 (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1205 fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301206
Simon Zhange7eba482019-08-25 15:30:45 +08001207 lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301208 lb0 = load_balance_get (lbi);
1209
1210 return (fib_urpf_check_size (lb0->lb_urpf));
1211}
1212
rootc9d1c5b2017-08-15 12:58:31 -04001213always_inline u8
1214ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1215 u32 * udp_offset0)
1216{
1217 u32 proto0;
1218 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1219 if (proto0 != IP_PROTOCOL_UDP)
1220 {
1221 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1222 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1223 }
1224 return proto0;
1225}
1226
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001227/* *INDENT-OFF* */
1228VNET_FEATURE_ARC_INIT (ip6_local) =
1229{
1230 .arc_name = "ip6-local",
1231 .start_nodes = VNET_FEATURES ("ip6-local"),
1232};
1233/* *INDENT-ON* */
1234
johny17478e42019-10-11 18:28:51 +02001235static_always_inline u8
1236ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
1237{
1238
1239 u16 payload_length_host_byte_order;
1240 u32 n_this_buffer, n_bytes_left;
1241 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1242 u32 headers_size = sizeof (ip0[0]);
1243 u8 *data_this_buffer;
1244
1245
1246 data_this_buffer = (u8 *) (ip0 + 1);
1247
1248 ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1249
1250 /* validate really icmp6 next */
1251
1252 if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1253 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1254 return 0;
1255
1256
1257 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1258 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1259
johnya633a432019-12-06 13:58:35 +01001260
1261 u32 n_ip_bytes_this_buffer =
1262 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1263 if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
johny17478e42019-10-11 18:28:51 +02001264 {
johnya633a432019-12-06 13:58:35 +01001265 n_this_buffer = p0->current_length > headers_size ?
1266 n_ip_bytes_this_buffer - headers_size : 0;
johny17478e42019-10-11 18:28:51 +02001267 }
1268
1269 n_bytes_left -= n_this_buffer;
1270 n_bytes_left -= p0->total_length_not_including_first_buffer;
1271
1272 if (n_bytes_left == 0)
1273 return 0;
1274 else
1275 return 1;
1276}
1277
1278
Benoît Ganne26a10192019-02-14 15:32:45 +01001279always_inline uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001280ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1281 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001283 ip6_main_t *im = &ip6_main;
1284 ip_lookup_main_t *lm = &im->lookup_main;
Benoît Ganne26a10192019-02-14 15:32:45 +01001285 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 vlib_node_runtime_t *error_node =
1287 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001288 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001289 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1290 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291
1292 from = vlib_frame_vector_args (frame);
1293 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001294
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 if (node->flags & VLIB_NODE_FLAG_TRACE)
1296 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1297
Benoît Ganne26a10192019-02-14 15:32:45 +01001298 vlib_get_buffers (vm, from, bufs, n_left_from);
1299 b = bufs;
1300 next = nexts;
1301
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001302 while (n_left_from > 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001304 /* Prefetch next iteration. */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001305 if (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001307 vlib_prefetch_buffer_header (b[4], STORE);
1308 vlib_prefetch_buffer_header (b[5], STORE);
1309 vlib_prefetch_buffer_data (b[2], LOAD);
1310 vlib_prefetch_buffer_data (b[3], LOAD);
Benoît Ganne26a10192019-02-14 15:32:45 +01001311 }
Dave Barach75fc8542016-10-11 16:16:02 -04001312
Neale Rannsf6472e02020-12-18 09:42:18 +00001313 ip6_error_t error[2];
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001314 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1315 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
Dave Barach75fc8542016-10-11 16:16:02 -04001316
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001317 ip6_header_t *ip[2];
1318 ip[0] = vlib_buffer_get_current (b[0]);
1319 ip[1] = vlib_buffer_get_current (b[1]);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001320
Benoît Ganne26a10192019-02-14 15:32:45 +01001321 if (head_of_feature_arc)
1322 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001323 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1324 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001326 u8 type[2];
1327 type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1328 type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001330 u32 flags[2];
1331 flags[0] = b[0]->flags;
1332 flags[1] = b[1]->flags;
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001333
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +02001334 vnet_buffer_oflags_t oflags[2];
Mohsin Kazmia7e830e2021-04-23 15:16:50 +02001335 oflags[0] = vnet_buffer (b[0])->oflags;
1336 oflags[1] = vnet_buffer (b[1])->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +01001337
1338 u32 l4_offload[2];
1339 l4_offload[0] = (flags[0] & VNET_BUFFER_F_OFFLOAD) &&
1340 (oflags[0] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1341 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1342 l4_offload[1] = (flags[1] & VNET_BUFFER_F_OFFLOAD) &&
1343 (oflags[1] & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1344 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1345
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001346 u32 good_l4_csum[2];
1347 good_l4_csum[0] =
Mohsin Kazmi68095382021-02-10 11:26:24 +01001348 (flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[0];
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001349 good_l4_csum[1] =
Mohsin Kazmi68095382021-02-10 11:26:24 +01001350 (flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload[1];
Filip Tehlarb601f222017-01-02 10:22:56 +01001351
Damjan Marion34e823f2019-02-19 08:55:18 +01001352 u32 udp_offset[2] = { };
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001353 u8 is_tcp_udp[2];
1354 is_tcp_udp[0] =
1355 ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1356 is_tcp_udp[1] =
1357 ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1358 i16 len_diff[2] = { 0 };
1359 if (PREDICT_TRUE (is_tcp_udp[0]))
Shwethab78292e2016-09-13 11:51:00 +01001360 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001361 udp_header_t *udp =
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001362 (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1363 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
Benoît Ganne26a10192019-02-14 15:32:45 +01001364 && udp->checksum == 0;
1365 /* optimistically verify UDP length. */
1366 u16 ip_len, udp_len;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001367 ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
Benoît Ganne26a10192019-02-14 15:32:45 +01001368 udp_len = clib_net_to_host_u16 (udp->length);
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001369 len_diff[0] = ip_len - udp_len;
Shwethab78292e2016-09-13 11:51:00 +01001370 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001371 if (PREDICT_TRUE (is_tcp_udp[1]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001373 udp_header_t *udp =
1374 (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1375 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1376 && udp->checksum == 0;
1377 /* optimistically verify UDP length. */
1378 u16 ip_len, udp_len;
1379 ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1380 udp_len = clib_net_to_host_u16 (udp->length);
1381 len_diff[1] = ip_len - udp_len;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382 }
1383
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001384 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1385 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1386
1387 len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1388 len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1389
1390 u8 need_csum[2];
1391 need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1392 && !good_l4_csum[0]
1393 && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1394 need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1395 && !good_l4_csum[1]
1396 && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1397 if (PREDICT_FALSE (need_csum[0]))
1398 {
1399 flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1400 good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001401 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1402 }
1403 else
1404 {
1405 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1406 error[0] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001407 }
1408 if (PREDICT_FALSE (need_csum[1]))
1409 {
1410 flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1411 good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001412 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1413 }
1414 else
1415 {
1416 if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1417 error[1] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001418 }
1419
johny17478e42019-10-11 18:28:51 +02001420
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001421 error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
johny17478e42019-10-11 18:28:51 +02001422
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001423 error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424
Benoît Ganne26a10192019-02-14 15:32:45 +01001425 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1426 IP6_ERROR_UDP_CHECKSUM,
1427 "Wrong IP6 errors constants");
1428 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1429 IP6_ERROR_ICMP_CHECKSUM,
1430 "Wrong IP6 errors constants");
1431
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001432 error[0] =
1433 !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1434 error[1] =
1435 !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001436
1437 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001438 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001439 u8 unroutable[2];
1440 unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1441 && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1442 && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
1443 unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1444 && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1445 && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
1446 if (PREDICT_FALSE (unroutable[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001447 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001448 error[0] =
1449 !ip6_urpf_loose_check (im, b[0],
1450 ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1451 : error[0];
1452 }
1453 if (PREDICT_FALSE (unroutable[1]))
1454 {
1455 error[1] =
1456 !ip6_urpf_loose_check (im, b[1],
1457 ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1458 : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001459 }
1460
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001461 vnet_buffer (b[0])->ip.fib_index =
1462 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1463 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1464 vnet_buffer (b[0])->ip.fib_index;
1465 vnet_buffer (b[1])->ip.fib_index =
1466 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1467 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1468 vnet_buffer (b[1])->ip.fib_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001469 } /* head_of_feature_arc */
Florin Corascea194d2017-10-02 00:18:51 -07001470
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001471 next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1472 next[0] =
1473 error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1474 next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1475 next[1] =
1476 error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
Florin Corascea194d2017-10-02 00:18:51 -07001477
Benoît Gannec15539a2021-01-19 16:40:07 +01001478 b[0]->error = error_node->errors[error[0]];
1479 b[1]->error = error_node->errors[error[1]];
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001480
Benoît Ganne26a10192019-02-14 15:32:45 +01001481 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001482 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001483 u8 ip6_unknown[2];
1484 ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1485 ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1486 if (PREDICT_TRUE (ip6_unknown[0]))
Shwethab78292e2016-09-13 11:51:00 +01001487 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001488 u32 next32 = next[0];
Benoît Ganne26a10192019-02-14 15:32:45 +01001489 vnet_feature_arc_start (arc_index,
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001490 vnet_buffer (b[0])->sw_if_index
1491 [VLIB_RX], &next32, b[0]);
1492 next[0] = next32;
1493 }
1494 if (PREDICT_TRUE (ip6_unknown[1]))
1495 {
1496 u32 next32 = next[1];
1497 vnet_feature_arc_start (arc_index,
1498 vnet_buffer (b[1])->sw_if_index
1499 [VLIB_RX], &next32, b[1]);
1500 next[1] = next32;
Shwethab78292e2016-09-13 11:51:00 +01001501 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502 }
Dave Barach75fc8542016-10-11 16:16:02 -04001503
Benoît Ganne26a10192019-02-14 15:32:45 +01001504 /* next */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001505 b += 2;
1506 next += 2;
1507 n_left_from -= 2;
Benoît Ganne26a10192019-02-14 15:32:45 +01001508 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001509
Benoît Ganne26a10192019-02-14 15:32:45 +01001510 while (n_left_from)
1511 {
1512 u8 error;
1513 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1514
1515 ip6_header_t *ip;
1516 ip = vlib_buffer_get_current (b[0]);
1517
1518 if (head_of_feature_arc)
1519 {
1520 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1521 u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
1522
1523 u32 flags = b[0]->flags;
Benoît Ganne26a10192019-02-14 15:32:45 +01001524
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +02001525 vnet_buffer_oflags_t oflags = vnet_buffer (b[0])->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +01001526
1527 u32 l4_offload = (flags & VNET_BUFFER_F_OFFLOAD) &&
1528 (oflags & (VNET_BUFFER_OFFLOAD_F_TCP_CKSUM |
1529 VNET_BUFFER_OFFLOAD_F_UDP_CKSUM));
1530
1531 u32 good_l4_csum =
1532 (flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) | l4_offload;
Benoît Ganne26a10192019-02-14 15:32:45 +01001533 u32 udp_offset;
1534 i16 len_diff = 0;
1535 u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1536 if (PREDICT_TRUE (is_tcp_udp))
1537 {
1538 udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1539 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1540 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1541 && udp->checksum == 0;
1542 /* optimistically verify UDP length. */
1543 u16 ip_len, udp_len;
1544 ip_len = clib_net_to_host_u16 (ip->payload_length);
1545 udp_len = clib_net_to_host_u16 (udp->length);
1546 len_diff = ip_len - udp_len;
1547 }
1548
1549 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1550 len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1551
Mohsin Kazmi68095382021-02-10 11:26:24 +01001552 u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN &&
1553 !good_l4_csum &&
1554 !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
Benoît Ganne26a10192019-02-14 15:32:45 +01001555 if (PREDICT_FALSE (need_csum))
1556 {
1557 flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1558 good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001559 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1560 }
1561 else
1562 {
1563 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1564 error = IP6_ERROR_BAD_LENGTH;
Benoît Ganne26a10192019-02-14 15:32:45 +01001565 }
1566
johny17478e42019-10-11 18:28:51 +02001567
1568
Benoît Ganne26a10192019-02-14 15:32:45 +01001569 error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
Benoît Ganne26a10192019-02-14 15:32:45 +01001570 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1571 IP6_ERROR_UDP_CHECKSUM,
1572 "Wrong IP6 errors constants");
1573 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1574 IP6_ERROR_ICMP_CHECKSUM,
1575 "Wrong IP6 errors constants");
1576
1577 error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1578
1579 /* Drop packets from unroutable hosts. */
1580 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1581 u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1582 && type != IP_BUILTIN_PROTOCOL_ICMP
1583 && !ip6_address_is_link_local_unicast (&ip->src_address);
1584 if (PREDICT_FALSE (unroutable))
1585 {
1586 error =
1587 !ip6_urpf_loose_check (im, b[0],
1588 ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1589 error;
1590 }
1591
1592 vnet_buffer (b[0])->ip.fib_index =
1593 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1594 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1595 vnet_buffer (b[0])->ip.fib_index;
1596 } /* head_of_feature_arc */
1597
1598 next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1599 next[0] =
1600 error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1601
Benoît Gannec15539a2021-01-19 16:40:07 +01001602 b[0]->error = error_node->errors[error];
Benoît Ganne26a10192019-02-14 15:32:45 +01001603
1604 if (head_of_feature_arc)
1605 {
1606 if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1607 {
1608 u32 next32 = next[0];
1609 vnet_feature_arc_start (arc_index,
1610 vnet_buffer (b[0])->sw_if_index
1611 [VLIB_RX], &next32, b[0]);
1612 next[0] = next32;
1613 }
1614 }
1615
1616 /* next */
1617 b += 1;
1618 next += 1;
1619 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620 }
1621
Benoît Ganne26a10192019-02-14 15:32:45 +01001622 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623 return frame->n_vectors;
1624}
1625
Damjan Marion38173502019-02-13 19:30:09 +01001626VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1627 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001628{
1629 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1630}
1631
Dave Barachd7cb1b52016-12-09 09:52:16 -05001632/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001633VLIB_REGISTER_NODE (ip6_local_node) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001634{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635 .name = "ip6-local",
1636 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001637 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001638 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001639 .next_nodes =
1640 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001641 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1642 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001643 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1644 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001645 [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 },
1647};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001648/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649
Damjan Marion38173502019-02-13 19:30:09 +01001650VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
1651 vlib_node_runtime_t * node,
1652 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001653{
1654 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1655}
1656
1657/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001658VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001659 .name = "ip6-local-end-of-arc",
1660 .vector_size = sizeof (u32),
1661
1662 .format_trace = format_ip6_forward_next_trace,
1663 .sibling_of = "ip6-local",
1664};
1665
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001666VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1667 .arc_name = "ip6-local",
1668 .node_name = "ip6-local-end-of-arc",
1669 .runs_before = 0, /* not before any other features */
1670};
1671/* *INDENT-ON* */
1672
Damjan Marion38173502019-02-13 19:30:09 +01001673#ifdef CLIB_MARCH_VARIANT
1674extern vlib_node_registration_t ip6_local_node;
Damjan Marion38173502019-02-13 19:30:09 +01001675#else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001676void
1677ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 vlib_main_t *vm = vlib_get_main ();
1680 ip6_main_t *im = &ip6_main;
1681 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001682
1683 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001684 lm->local_next_by_ip_protocol[protocol] =
1685 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001686}
1687
Neale Rannsb538dd82019-05-21 06:54:54 -07001688void
1689ip6_unregister_protocol (u32 protocol)
1690{
1691 ip6_main_t *im = &ip6_main;
1692 ip_lookup_main_t *lm = &im->lookup_main;
1693
1694 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1695 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1696}
Damjan Marion38173502019-02-13 19:30:09 +01001697#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001698
Dave Barachd7cb1b52016-12-09 09:52:16 -05001699typedef enum
1700{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001701 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001702 IP6_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001703 IP6_REWRITE_NEXT_FRAGMENT,
1704 IP6_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001705} ip6_rewrite_next_t;
1706
Neale Ranns889fe942017-06-01 05:43:19 -04001707/**
1708 * This bits of an IPv6 address to mask to construct a multicast
1709 * MAC address
1710 */
1711#define IP6_MCAST_ADDR_MASK 0xffffffff
1712
Ole Troanda6e11b2018-05-23 11:21:42 +02001713always_inline void
1714ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
Ole Troan313f7e22018-04-10 16:02:51 +02001715 u16 adj_packet_bytes, bool is_locally_generated,
Ole Troaneb284a12019-10-09 13:33:19 +02001716 u32 * next, u8 is_midchain, u32 * error)
Ole Troanda6e11b2018-05-23 11:21:42 +02001717{
1718 if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1719 {
Ole Troan313f7e22018-04-10 16:02:51 +02001720 if (is_locally_generated)
1721 {
1722 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02001723 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001724 (is_midchain ?
1725 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1726 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02001727 *next = IP6_REWRITE_NEXT_FRAGMENT;
Ole Troan282093f2018-09-19 12:38:51 +02001728 *error = IP6_ERROR_MTU_EXCEEDED;
Ole Troan313f7e22018-04-10 16:02:51 +02001729 }
1730 else
1731 {
1732 *error = IP6_ERROR_MTU_EXCEEDED;
1733 icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1734 adj_packet_bytes);
1735 *next = IP6_REWRITE_NEXT_ICMP_ERROR;
1736 }
Ole Troanda6e11b2018-05-23 11:21:42 +02001737 }
1738}
1739
Ed Warnickecb9cada2015-12-08 15:45:58 -07001740always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001741ip6_rewrite_inline_with_gso (vlib_main_t * vm,
1742 vlib_node_runtime_t * node,
1743 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001744 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001745{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001746 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1747 u32 *from = vlib_frame_vector_args (frame);
1748 u32 n_left_from, n_left_to_next, *to_next, next_index;
1749 vlib_node_runtime_t *error_node =
1750 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751
1752 n_left_from = frame->n_vectors;
1753 next_index = node->cached_next_index;
Damjan Marion067cd622018-07-11 12:47:43 +02001754 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001755
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 while (n_left_from > 0)
1757 {
1758 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1759
1760 while (n_left_from >= 4 && n_left_to_next >= 2)
1761 {
Neale Ranns960eeea2019-12-02 23:28:50 +00001762 const ip_adjacency_t *adj0, *adj1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 vlib_buffer_t *p0, *p1;
1764 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765 u32 pi0, rw_len0, next0, error0, adj_index0;
1766 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001767 u32 tx_sw_if_index0, tx_sw_if_index1;
Ole Troan313f7e22018-04-10 16:02:51 +02001768 bool is_locally_originated0, is_locally_originated1;
Dave Barach75fc8542016-10-11 16:16:02 -04001769
Ed Warnickecb9cada2015-12-08 15:45:58 -07001770 /* Prefetch next iteration. */
1771 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001772 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773
1774 p2 = vlib_get_buffer (vm, from[2]);
1775 p3 = vlib_get_buffer (vm, from[3]);
1776
1777 vlib_prefetch_buffer_header (p2, LOAD);
1778 vlib_prefetch_buffer_header (p3, LOAD);
1779
Damjan Marionaf7fb042021-07-15 11:54:41 +02001780 clib_prefetch_store (p2->pre_data);
1781 clib_prefetch_store (p3->pre_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782
1783 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1784 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1785 }
1786
1787 pi0 = to_next[0] = from[0];
1788 pi1 = to_next[1] = from[1];
1789
1790 from += 2;
1791 n_left_from -= 2;
1792 to_next += 2;
1793 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001794
Ed Warnickecb9cada2015-12-08 15:45:58 -07001795 p0 = vlib_get_buffer (vm, pi0);
1796 p1 = vlib_get_buffer (vm, pi1);
1797
Neale Rannsf06aea52016-11-29 06:51:37 -08001798 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1799 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001800
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801 ip0 = vlib_buffer_get_current (p0);
1802 ip1 = vlib_buffer_get_current (p1);
1803
1804 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001805 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806
Ole Troan313f7e22018-04-10 16:02:51 +02001807 is_locally_originated0 =
1808 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1809 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001810 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001811 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812
1813 /* Input node should have reject packets with hop limit 0. */
1814 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815
1816 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817
1818 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819
Dave Barachd7cb1b52016-12-09 09:52:16 -05001820 /*
1821 * If the hop count drops below 1 when forwarding, generate
1822 * an ICMP response.
1823 */
1824 if (PREDICT_FALSE (hop_limit0 <= 0))
1825 {
1826 error0 = IP6_ERROR_TIME_EXPIRED;
1827 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1828 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1829 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1830 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1831 0);
1832 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001833 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001834
Ole Troan313f7e22018-04-10 16:02:51 +02001835 is_locally_originated1 =
1836 p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1837 if (PREDICT_TRUE (!is_locally_originated1))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001838 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001839 i32 hop_limit1 = ip1->hop_limit;
1840
1841 /* Input node should have reject packets with hop limit 0. */
1842 ASSERT (ip1->hop_limit > 0);
1843
1844 hop_limit1 -= 1;
1845
1846 ip1->hop_limit = hop_limit1;
1847
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 /*
1849 * If the hop count drops below 1 when forwarding, generate
1850 * an ICMP response.
1851 */
1852 if (PREDICT_FALSE (hop_limit1 <= 0))
1853 {
1854 error1 = IP6_ERROR_TIME_EXPIRED;
1855 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1856 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1857 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1858 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1859 0);
1860 }
1861 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001862
Neale Ranns107e7d42017-04-11 09:55:19 -07001863 adj0 = adj_get (adj_index0);
1864 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001865
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866 rw_len0 = adj0[0].rewrite_header.data_bytes;
1867 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001868 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1869 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001870
Neale Ranns9c6a6132017-02-21 05:33:14 -08001871 if (do_counters)
1872 {
1873 vlib_increment_combined_counter
1874 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001875 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001876 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1877 vlib_increment_combined_counter
1878 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001879 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001880 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1881 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882
1883 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001884 u16 ip0_len =
1885 clib_net_to_host_u16 (ip0->payload_length) +
1886 sizeof (ip6_header_t);
1887 u16 ip1_len =
1888 clib_net_to_host_u16 (ip1->payload_length) +
1889 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001890 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001891 ip0_len = gso_mtu_sz (p0);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001892 if (p1->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001893 ip1_len = gso_mtu_sz (p1);
1894
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001895 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001896 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001897 is_locally_originated0, &next0, is_midchain,
1898 &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001899 ip6_mtu_check (p1, ip1_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001900 adj1[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001901 is_locally_originated1, &next1, is_midchain,
1902 &error1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001903 /* Don't adjust the buffer for hop count issue; icmp-error node
Jim Thompsonf324dec2019-04-08 03:22:21 -05001904 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001905 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1906 {
1907 p0->current_data -= rw_len0;
1908 p0->current_length += rw_len0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001909 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1910 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1911 next0 = adj0[0].rewrite_header.next_index;
Neale Rannsb069a692017-03-15 12:34:25 -04001912 if (PREDICT_FALSE
1913 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001914 vnet_feature_arc_start_w_cfg_index
1915 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
1916 adj0->ia_cfg_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001918 else
1919 {
1920 p0->error = error_node->errors[error0];
1921 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1923 {
1924 p1->current_data -= rw_len1;
1925 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926
Dave Barachd7cb1b52016-12-09 09:52:16 -05001927 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1928 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1929 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001930
Neale Rannsb069a692017-03-15 12:34:25 -04001931 if (PREDICT_FALSE
1932 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001933 vnet_feature_arc_start_w_cfg_index
1934 (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1,
1935 adj1->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001936 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001937 else
1938 {
1939 p1->error = error_node->errors[error1];
1940 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941
Neale Ranns25edf142019-03-22 08:12:48 +00001942 if (is_midchain)
1943 {
1944 /* before we paint on the next header, update the L4
1945 * checksums if required, since there's no offload on a tunnel */
Dave Barach1bd2c012020-04-12 08:31:39 -04001946 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001947 1 /* is_ip6 */ );
Dave Barach1bd2c012020-04-12 08:31:39 -04001948 vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001949 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00001950
Neale Ranns4ec36c52020-03-31 09:21:29 -04001951 /* Guess we are only writing on ipv6 header. */
1952 vnet_rewrite_two_headers (adj0[0], adj1[0],
1953 ip0, ip1, sizeof (ip6_header_t));
1954 }
1955 else
1956 /* Guess we are only writing on simple Ethernet header. */
1957 vnet_rewrite_two_headers (adj0[0], adj1[0],
1958 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001959
1960 if (is_midchain)
1961 {
Neale Ranns25edf142019-03-22 08:12:48 +00001962 if (adj0->sub_type.midchain.fixup_func)
1963 adj0->sub_type.midchain.fixup_func
1964 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1965 if (adj1->sub_type.midchain.fixup_func)
1966 adj1->sub_type.midchain.fixup_func
1967 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001968 }
1969 if (is_mcast)
1970 {
1971 /*
1972 * copy bytes from the IP address into the MAC rewrite
1973 */
Neale Ranns889fe942017-06-01 05:43:19 -04001974 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1975 adj0->
1976 rewrite_header.dst_mcast_offset,
1977 &ip0->dst_address.as_u32[3],
1978 (u8 *) ip0);
1979 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1980 adj1->
1981 rewrite_header.dst_mcast_offset,
1982 &ip1->dst_address.as_u32[3],
1983 (u8 *) ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001984 }
Neale Ranns5e575b12016-10-03 09:40:25 +01001985
Ed Warnickecb9cada2015-12-08 15:45:58 -07001986 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1987 to_next, n_left_to_next,
1988 pi0, pi1, next0, next1);
1989 }
1990
1991 while (n_left_from > 0 && n_left_to_next > 0)
1992 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993 ip_adjacency_t *adj0;
1994 vlib_buffer_t *p0;
1995 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001996 u32 pi0, rw_len0;
1997 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001998 u32 tx_sw_if_index0;
Ole Troan313f7e22018-04-10 16:02:51 +02001999 bool is_locally_originated0;
Dave Barach75fc8542016-10-11 16:16:02 -04002000
Ed Warnickecb9cada2015-12-08 15:45:58 -07002001 pi0 = to_next[0] = from[0];
2002
2003 p0 = vlib_get_buffer (vm, pi0);
2004
Neale Rannsf06aea52016-11-29 06:51:37 -08002005 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006
Neale Ranns107e7d42017-04-11 09:55:19 -07002007 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002008
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009 ip0 = vlib_buffer_get_current (p0);
2010
2011 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002012 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013
2014 /* Check hop limit */
Ole Troan313f7e22018-04-10 16:02:51 +02002015 is_locally_originated0 =
2016 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
2017 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 {
2019 i32 hop_limit0 = ip0->hop_limit;
2020
2021 ASSERT (ip0->hop_limit > 0);
2022
2023 hop_limit0 -= 1;
2024
2025 ip0->hop_limit = hop_limit0;
2026
Dave Barachd7cb1b52016-12-09 09:52:16 -05002027 if (PREDICT_FALSE (hop_limit0 <= 0))
2028 {
2029 /*
2030 * If the hop count drops below 1 when forwarding, generate
2031 * an ICMP response.
2032 */
2033 error0 = IP6_ERROR_TIME_EXPIRED;
2034 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2035 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2036 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2037 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2038 0);
2039 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040 }
2041
Neale Ranns25edf142019-03-22 08:12:48 +00002042 if (is_midchain)
2043 {
Dave Barach1bd2c012020-04-12 08:31:39 -04002044 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002045 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00002046
Neale Ranns4ec36c52020-03-31 09:21:29 -04002047 /* Guess we are only writing on ip6 header. */
2048 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t));
2049 }
2050 else
2051 /* Guess we are only writing on simple Ethernet header. */
2052 vnet_rewrite_one_header (adj0[0], ip0,
2053 sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002054
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055 /* Update packet buffer attributes/set output interface. */
2056 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002057 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002058
Neale Ranns9c6a6132017-02-21 05:33:14 -08002059 if (do_counters)
2060 {
2061 vlib_increment_combined_counter
2062 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002063 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002064 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2065 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002066
2067 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002068 u16 ip0_len =
2069 clib_net_to_host_u16 (ip0->payload_length) +
2070 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002071 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002072 ip0_len = gso_mtu_sz (p0);
2073
2074 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02002075 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02002076 is_locally_originated0, &next0, is_midchain,
2077 &error0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002078 /* Don't adjust the buffer for hop count issue; icmp-error node
Ole Troanda6e11b2018-05-23 11:21:42 +02002079 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002080 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2081 {
Chris Luke816f3e12016-06-14 16:24:47 -04002082 p0->current_data -= rw_len0;
2083 p0->current_length += rw_len0;
2084
Dave Barachd7cb1b52016-12-09 09:52:16 -05002085 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002086
Dave Barachd7cb1b52016-12-09 09:52:16 -05002087 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2088 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002089
Neale Rannsb069a692017-03-15 12:34:25 -04002090 if (PREDICT_FALSE
2091 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002092 vnet_feature_arc_start_w_cfg_index
2093 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
2094 adj0->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002095 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002096 else
2097 {
2098 p0->error = error_node->errors[error0];
2099 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002100
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002101 if (is_midchain)
2102 {
Neale Ranns25edf142019-03-22 08:12:48 +00002103 if (adj0->sub_type.midchain.fixup_func)
2104 adj0->sub_type.midchain.fixup_func
2105 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002106 }
2107 if (is_mcast)
2108 {
Neale Ranns889fe942017-06-01 05:43:19 -04002109 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2110 adj0->
2111 rewrite_header.dst_mcast_offset,
2112 &ip0->dst_address.as_u32[3],
2113 (u8 *) ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002114 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002115
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116 from += 1;
2117 n_left_from -= 1;
2118 to_next += 1;
2119 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002120
Ed Warnickecb9cada2015-12-08 15:45:58 -07002121 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2122 to_next, n_left_to_next,
2123 pi0, next0);
2124 }
2125
2126 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2127 }
2128
2129 /* Need to do trace after rewrites to pick up new packet data. */
2130 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002131 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
2133 return frame->n_vectors;
2134}
2135
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002136always_inline uword
2137ip6_rewrite_inline (vlib_main_t * vm,
2138 vlib_node_runtime_t * node,
2139 vlib_frame_t * frame,
2140 int do_counters, int is_midchain, int is_mcast)
2141{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002142 return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2143 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002144}
2145
Damjan Marion38173502019-02-13 19:30:09 +01002146VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
2147 vlib_node_runtime_t * node,
2148 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002150 if (adj_are_counters_enabled ())
2151 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2152 else
2153 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002154}
2155
Damjan Marion38173502019-02-13 19:30:09 +01002156VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
2157 vlib_node_runtime_t * node,
2158 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002159{
2160 if (adj_are_counters_enabled ())
2161 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2162 else
2163 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2164}
2165
Damjan Marion38173502019-02-13 19:30:09 +01002166VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
2167 vlib_node_runtime_t * node,
2168 vlib_frame_t * frame)
Neale Ranns32e1c012016-11-22 17:07:28 +00002169{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002170 if (adj_are_counters_enabled ())
2171 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2172 else
2173 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002174}
2175
Damjan Marion38173502019-02-13 19:30:09 +01002176VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
2177 vlib_node_runtime_t * node,
2178 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002179{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002180 if (adj_are_counters_enabled ())
2181 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2182 else
2183 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002184}
2185
Damjan Marion38173502019-02-13 19:30:09 +01002186VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
2187 vlib_node_runtime_t * node,
2188 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002189{
2190 if (adj_are_counters_enabled ())
2191 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2192 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002193 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002194}
2195
Dave Barachd7cb1b52016-12-09 09:52:16 -05002196/* *INDENT-OFF* */
2197VLIB_REGISTER_NODE (ip6_midchain_node) =
2198{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002199 .name = "ip6-midchain",
2200 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002201 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002202 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002203 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002204
Dave Barachd7cb1b52016-12-09 09:52:16 -05002205VLIB_REGISTER_NODE (ip6_rewrite_node) =
2206{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002207 .name = "ip6-rewrite",
2208 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002209 .format_trace = format_ip6_rewrite_trace,
Ole Troan313f7e22018-04-10 16:02:51 +02002210 .n_next_nodes = IP6_REWRITE_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002211 .next_nodes =
2212 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002213 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002214 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002215 [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002216 },
2217};
2218
Neale Ranns1855b8e2018-07-11 10:31:26 -07002219VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002220 .name = "ip6-rewrite-bcast",
2221 .vector_size = sizeof (u32),
2222
2223 .format_trace = format_ip6_rewrite_trace,
2224 .sibling_of = "ip6-rewrite",
2225};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002226
Neale Ranns32e1c012016-11-22 17:07:28 +00002227VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2228{
Neale Ranns32e1c012016-11-22 17:07:28 +00002229 .name = "ip6-rewrite-mcast",
2230 .vector_size = sizeof (u32),
2231 .format_trace = format_ip6_rewrite_trace,
2232 .sibling_of = "ip6-rewrite",
2233};
Neale Ranns32e1c012016-11-22 17:07:28 +00002234
Neale Ranns32e1c012016-11-22 17:07:28 +00002235
Damjan Marion38173502019-02-13 19:30:09 +01002236VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002237{
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002238 .name = "ip6-mcast-midchain",
2239 .vector_size = sizeof (u32),
2240 .format_trace = format_ip6_rewrite_trace,
2241 .sibling_of = "ip6-rewrite",
2242};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002243
Neale Ranns1855b8e2018-07-11 10:31:26 -07002244/* *INDENT-ON* */
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002245
Ole Troan944f5482016-05-24 11:56:58 +02002246/*
2247 * Hop-by-Hop handling
2248 */
Benoît Ganne47727c02019-02-12 13:35:08 +01002249#ifndef CLIB_MARCH_VARIANT
Ole Troan944f5482016-05-24 11:56:58 +02002250ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01002251#endif /* CLIB_MARCH_VARIANT */
Ole Troan944f5482016-05-24 11:56:58 +02002252
2253#define foreach_ip6_hop_by_hop_error \
2254_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2255_(FORMAT, "incorrectly formatted hop-by-hop options") \
2256_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2257
Neale Ranns32e1c012016-11-22 17:07:28 +00002258/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002259typedef enum
2260{
Ole Troan944f5482016-05-24 11:56:58 +02002261#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2262 foreach_ip6_hop_by_hop_error
2263#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002264 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002265} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002266/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002267
2268/*
2269 * Primary h-b-h handler trace support
2270 * We work pretty hard on the problem for obvious reasons
2271 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002272typedef struct
2273{
Ole Troan944f5482016-05-24 11:56:58 +02002274 u32 next_index;
2275 u32 trace_len;
2276 u8 option_data[256];
2277} ip6_hop_by_hop_trace_t;
2278
Benoît Ganne47727c02019-02-12 13:35:08 +01002279extern vlib_node_registration_t ip6_hop_by_hop_node;
Ole Troan944f5482016-05-24 11:56:58 +02002280
Dave Barachd7cb1b52016-12-09 09:52:16 -05002281static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002282#define _(sym,string) string,
2283 foreach_ip6_hop_by_hop_error
2284#undef _
2285};
2286
Damjan Marion38173502019-02-13 19:30:09 +01002287#ifndef CLIB_MARCH_VARIANT
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302288u8 *
2289format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2290{
2291 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2292 int total_len = va_arg (*args, int);
2293 ip6_hop_by_hop_option_t *opt0, *limit0;
2294 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2295 u8 type0;
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302296 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2297 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2298
2299 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2300 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2301
2302 while (opt0 < limit0)
2303 {
2304 type0 = opt0->type;
2305 switch (type0)
2306 {
2307 case 0: /* Pad, just stop */
2308 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2309 break;
2310
2311 default:
2312 if (hm->trace[type0])
2313 {
2314 s = (*hm->trace[type0]) (s, opt0);
2315 }
2316 else
2317 {
Mohsin Kazmi68095382021-02-10 11:26:24 +01002318 s = format (s, "\n unrecognized option %d length %d", type0,
2319 opt0->length);
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302320 }
2321 opt0 =
2322 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2323 sizeof (ip6_hop_by_hop_option_t));
2324 break;
2325 }
2326 }
2327 return s;
2328}
Damjan Marion38173502019-02-13 19:30:09 +01002329#endif
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302330
Ole Troan944f5482016-05-24 11:56:58 +02002331static u8 *
2332format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2333{
2334 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2335 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002336 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002337 ip6_hop_by_hop_header_t *hbh0;
2338 ip6_hop_by_hop_option_t *opt0, *limit0;
2339 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2340
2341 u8 type0;
2342
Dave Barachd7cb1b52016-12-09 09:52:16 -05002343 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002344
2345 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002346 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002347
Dave Barachd7cb1b52016-12-09 09:52:16 -05002348 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2349 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002350
Dave Barachd7cb1b52016-12-09 09:52:16 -05002351 while (opt0 < limit0)
2352 {
2353 type0 = opt0->type;
2354 switch (type0)
2355 {
2356 case 0: /* Pad, just stop */
2357 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2358 break;
Ole Troan944f5482016-05-24 11:56:58 +02002359
Dave Barachd7cb1b52016-12-09 09:52:16 -05002360 default:
2361 if (hm->trace[type0])
2362 {
2363 s = (*hm->trace[type0]) (s, opt0);
2364 }
2365 else
2366 {
Mohsin Kazmi68095382021-02-10 11:26:24 +01002367 s = format (s, "\n unrecognized option %d length %d", type0,
2368 opt0->length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002369 }
2370 opt0 =
2371 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2372 sizeof (ip6_hop_by_hop_option_t));
2373 break;
2374 }
Ole Troan944f5482016-05-24 11:56:58 +02002375 }
Ole Troan944f5482016-05-24 11:56:58 +02002376 return s;
2377}
2378
Dave Barachd7cb1b52016-12-09 09:52:16 -05002379always_inline u8
2380ip6_scan_hbh_options (vlib_buffer_t * b0,
2381 ip6_header_t * ip0,
2382 ip6_hop_by_hop_header_t * hbh0,
2383 ip6_hop_by_hop_option_t * opt0,
2384 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002385{
2386 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2387 u8 type0;
2388 u8 error0 = 0;
2389
2390 while (opt0 < limit0)
2391 {
2392 type0 = opt0->type;
2393 switch (type0)
2394 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002395 case 0: /* Pad1 */
2396 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002397 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002398 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002399 break;
2400 default:
2401 if (hm->options[type0])
2402 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002403 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2404 {
Shwethaa91cbe62016-08-08 15:51:04 +01002405 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002406 return (error0);
2407 }
Shwethaa91cbe62016-08-08 15:51:04 +01002408 }
2409 else
2410 {
2411 /* Unrecognized mandatory option, check the two high order bits */
2412 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2413 {
2414 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2415 break;
2416 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2417 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2418 *next0 = IP_LOOKUP_NEXT_DROP;
2419 break;
2420 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2421 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2422 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002423 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2424 ICMP6_parameter_problem_unrecognized_option,
2425 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002426 break;
2427 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2428 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002429 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002430 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002431 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2432 icmp6_error_set_vnet_buffer (b0,
2433 ICMP6_parameter_problem,
2434 ICMP6_parameter_problem_unrecognized_option,
2435 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002436 }
2437 else
2438 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002439 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002440 }
2441 break;
2442 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002443 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002444 }
2445 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002446 opt0 =
2447 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2448 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002449 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002450 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002451}
2452
Ole Troan944f5482016-05-24 11:56:58 +02002453/*
2454 * Process the Hop-by-Hop Options header
2455 */
Damjan Marion38173502019-02-13 19:30:09 +01002456VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
2457 vlib_node_runtime_t * node,
2458 vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002459{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002460 vlib_node_runtime_t *error_node =
2461 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002462 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2463 u32 n_left_from, *from, *to_next;
2464 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002465
2466 from = vlib_frame_vector_args (frame);
2467 n_left_from = frame->n_vectors;
2468 next_index = node->cached_next_index;
2469
Dave Barachd7cb1b52016-12-09 09:52:16 -05002470 while (n_left_from > 0)
2471 {
2472 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002473
Dave Barachd7cb1b52016-12-09 09:52:16 -05002474 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002475
Dave Barachd7cb1b52016-12-09 09:52:16 -05002476 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002477 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002478 u32 bi0, bi1;
2479 vlib_buffer_t *b0, *b1;
2480 u32 next0, next1;
2481 ip6_header_t *ip0, *ip1;
2482 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2483 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2484 u8 error0 = 0, error1 = 0;
2485
2486 /* Prefetch next iteration. */
2487 {
2488 vlib_buffer_t *p2, *p3;
2489
2490 p2 = vlib_get_buffer (vm, from[2]);
2491 p3 = vlib_get_buffer (vm, from[3]);
2492
2493 vlib_prefetch_buffer_header (p2, LOAD);
2494 vlib_prefetch_buffer_header (p3, LOAD);
2495
2496 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2497 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002498 }
2499
Dave Barachd7cb1b52016-12-09 09:52:16 -05002500 /* Speculatively enqueue b0, b1 to the current next frame */
2501 to_next[0] = bi0 = from[0];
2502 to_next[1] = bi1 = from[1];
2503 from += 2;
2504 to_next += 2;
2505 n_left_from -= 2;
2506 n_left_to_next -= 2;
2507
2508 b0 = vlib_get_buffer (vm, bi0);
2509 b1 = vlib_get_buffer (vm, bi1);
2510
2511 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2512 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002513 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002514 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002515 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516
2517 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2518 next0 = adj0->lookup_next_index;
2519 next1 = adj1->lookup_next_index;
2520
2521 ip0 = vlib_buffer_get_current (b0);
2522 ip1 = vlib_buffer_get_current (b1);
2523 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2524 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2525 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2526 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2527 limit0 =
2528 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2529 ((hbh0->length + 1) << 3));
2530 limit1 =
2531 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2532 ((hbh1->length + 1) << 3));
2533
2534 /*
2535 * Basic validity checks
2536 */
2537 if ((hbh0->length + 1) << 3 >
2538 clib_net_to_host_u16 (ip0->payload_length))
2539 {
2540 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2541 next0 = IP_LOOKUP_NEXT_DROP;
2542 goto outdual;
2543 }
2544 /* Scan the set of h-b-h options, process ones that we understand */
2545 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2546
2547 if ((hbh1->length + 1) << 3 >
2548 clib_net_to_host_u16 (ip1->payload_length))
2549 {
2550 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2551 next1 = IP_LOOKUP_NEXT_DROP;
2552 goto outdual;
2553 }
2554 /* Scan the set of h-b-h options, process ones that we understand */
2555 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2556
2557 outdual:
2558 /* Has the classifier flagged this buffer for special treatment? */
2559 if (PREDICT_FALSE
2560 ((error0 == 0)
2561 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2562 next0 = hm->next_override;
2563
2564 /* Has the classifier flagged this buffer for special treatment? */
2565 if (PREDICT_FALSE
2566 ((error1 == 0)
2567 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2568 next1 = hm->next_override;
2569
2570 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2571 {
2572 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2573 {
2574 ip6_hop_by_hop_trace_t *t =
2575 vlib_add_trace (vm, node, b0, sizeof (*t));
2576 u32 trace_len = (hbh0->length + 1) << 3;
2577 t->next_index = next0;
2578 /* Capture the h-b-h option verbatim */
2579 trace_len =
2580 trace_len <
2581 ARRAY_LEN (t->option_data) ? trace_len :
2582 ARRAY_LEN (t->option_data);
2583 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002584 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002585 }
2586 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2587 {
2588 ip6_hop_by_hop_trace_t *t =
2589 vlib_add_trace (vm, node, b1, sizeof (*t));
2590 u32 trace_len = (hbh1->length + 1) << 3;
2591 t->next_index = next1;
2592 /* Capture the h-b-h option verbatim */
2593 trace_len =
2594 trace_len <
2595 ARRAY_LEN (t->option_data) ? trace_len :
2596 ARRAY_LEN (t->option_data);
2597 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002598 clib_memcpy_fast (t->option_data, hbh1, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002599 }
2600
2601 }
2602
2603 b0->error = error_node->errors[error0];
2604 b1->error = error_node->errors[error1];
2605
2606 /* verify speculative enqueue, maybe switch current next frame */
2607 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2608 n_left_to_next, bi0, bi1, next0,
2609 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002610 }
2611
Dave Barachd7cb1b52016-12-09 09:52:16 -05002612 while (n_left_from > 0 && n_left_to_next > 0)
2613 {
2614 u32 bi0;
2615 vlib_buffer_t *b0;
2616 u32 next0;
2617 ip6_header_t *ip0;
2618 ip6_hop_by_hop_header_t *hbh0;
2619 ip6_hop_by_hop_option_t *opt0, *limit0;
2620 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002621
Dave Barachd7cb1b52016-12-09 09:52:16 -05002622 /* Speculatively enqueue b0 to the current next frame */
2623 bi0 = from[0];
2624 to_next[0] = bi0;
2625 from += 1;
2626 to_next += 1;
2627 n_left_from -= 1;
2628 n_left_to_next -= 1;
2629
2630 b0 = vlib_get_buffer (vm, bi0);
2631 /*
2632 * Default use the next_index from the adjacency.
2633 * A HBH option rarely redirects to a different node
2634 */
2635 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002636 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002637 next0 = adj0->lookup_next_index;
2638
2639 ip0 = vlib_buffer_get_current (b0);
2640 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2641 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2642 limit0 =
2643 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2644 ((hbh0->length + 1) << 3));
2645
2646 /*
2647 * Basic validity checks
2648 */
2649 if ((hbh0->length + 1) << 3 >
2650 clib_net_to_host_u16 (ip0->payload_length))
2651 {
2652 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2653 next0 = IP_LOOKUP_NEXT_DROP;
2654 goto out0;
2655 }
2656
2657 /* Scan the set of h-b-h options, process ones that we understand */
2658 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2659
2660 out0:
2661 /* Has the classifier flagged this buffer for special treatment? */
2662 if (PREDICT_FALSE
2663 ((error0 == 0)
2664 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2665 next0 = hm->next_override;
2666
2667 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2668 {
2669 ip6_hop_by_hop_trace_t *t =
2670 vlib_add_trace (vm, node, b0, sizeof (*t));
2671 u32 trace_len = (hbh0->length + 1) << 3;
2672 t->next_index = next0;
2673 /* Capture the h-b-h option verbatim */
2674 trace_len =
2675 trace_len <
2676 ARRAY_LEN (t->option_data) ? trace_len :
2677 ARRAY_LEN (t->option_data);
2678 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002679 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002680 }
2681
2682 b0->error = error_node->errors[error0];
2683
2684 /* verify speculative enqueue, maybe switch current next frame */
2685 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2686 n_left_to_next, bi0, next0);
2687 }
2688 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002689 }
Ole Troan944f5482016-05-24 11:56:58 +02002690 return frame->n_vectors;
2691}
2692
Dave Barachd7cb1b52016-12-09 09:52:16 -05002693/* *INDENT-OFF* */
2694VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2695{
Ole Troan944f5482016-05-24 11:56:58 +02002696 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002697 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002698 .vector_size = sizeof (u32),
2699 .format_trace = format_ip6_hop_by_hop_trace,
2700 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002701 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002702 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002703 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002704};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002705/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002706
Ole Troan944f5482016-05-24 11:56:58 +02002707static clib_error_t *
2708ip6_hop_by_hop_init (vlib_main_t * vm)
2709{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002710 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Dave Barachb7b92992018-10-17 10:38:51 -04002711 clib_memset (hm->options, 0, sizeof (hm->options));
2712 clib_memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002713 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002714 return (0);
2715}
2716
2717VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2718
Damjan Marion38173502019-02-13 19:30:09 +01002719#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002720void
2721ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002722{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002723 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002724
2725 hm->next_override = next;
2726}
2727
Ole Troan944f5482016-05-24 11:56:58 +02002728int
2729ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002730 int options (vlib_buffer_t * b, ip6_header_t * ip,
2731 ip6_hop_by_hop_option_t * opt),
2732 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002733{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002734 ip6_main_t *im = &ip6_main;
2735 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002736
Neale Ranns756cd942018-04-06 09:18:11 -07002737 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002738
2739 /* Already registered */
2740 if (hm->options[option])
2741 return (-1);
2742
2743 hm->options[option] = options;
2744 hm->trace[option] = trace;
2745
2746 /* Set global variable */
2747 im->hbh_enabled = 1;
2748
2749 return (0);
2750}
2751
2752int
2753ip6_hbh_unregister_option (u8 option)
2754{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002755 ip6_main_t *im = &ip6_main;
2756 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002757
Neale Ranns756cd942018-04-06 09:18:11 -07002758 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002759
2760 /* Not registered */
2761 if (!hm->options[option])
2762 return (-1);
2763
2764 hm->options[option] = NULL;
2765 hm->trace[option] = NULL;
2766
2767 /* Disable global knob if this was the last option configured */
2768 int i;
2769 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002770 for (i = 0; i < 256; i++)
2771 {
2772 if (hm->options[option])
2773 {
2774 found = true;
2775 break;
2776 }
Ole Troan944f5482016-05-24 11:56:58 +02002777 }
Ole Troan944f5482016-05-24 11:56:58 +02002778 if (!found)
2779 im->hbh_enabled = 0;
2780
2781 return (0);
2782}
2783
Ed Warnickecb9cada2015-12-08 15:45:58 -07002784/* Global IP6 main. */
2785ip6_main_t ip6_main;
Damjan Marion38173502019-02-13 19:30:09 +01002786#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002787
2788static clib_error_t *
2789ip6_lookup_init (vlib_main_t * vm)
2790{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002791 ip6_main_t *im = &ip6_main;
2792 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002793 uword i;
2794
Damjan Marion8b3191e2016-11-09 19:54:20 +01002795 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2796 return error;
2797
Ed Warnickecb9cada2015-12-08 15:45:58 -07002798 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2799 {
2800 u32 j, i0, i1;
2801
2802 i0 = i / 32;
2803 i1 = i % 32;
2804
2805 for (j = 0; j < i0; j++)
2806 im->fib_masks[i].as_u32[j] = ~0;
2807
2808 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002809 im->fib_masks[i].as_u32[i0] =
2810 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002811 }
2812
2813 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2814
Ed Warnickecb9cada2015-12-08 15:45:58 -07002815 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07002816 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2817 FIB_SOURCE_DEFAULT_ROUTE);
2818 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2819 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002820
2821 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002822 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002823 pn = pg_get_node (ip6_lookup_node.index);
2824 pn->unformat_edit = unformat_pg_ip6_header;
2825 }
2826
Ole Troan944f5482016-05-24 11:56:58 +02002827 /* Unless explicitly configured, don't process HBH options */
2828 im->hbh_enabled = 0;
2829
Dave Barach203c6322016-06-26 10:29:03 -04002830 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002831}
2832
2833VLIB_INIT_FUNCTION (ip6_lookup_init);
2834
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835static clib_error_t *
2836set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002837 unformat_input_t * input,
2838 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002839{
2840 int matched = 0;
2841 u32 table_id = 0;
2842 u32 flow_hash_config = 0;
2843 int rv;
2844
Dave Barachd7cb1b52016-12-09 09:52:16 -05002845 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2846 {
2847 if (unformat (input, "table %d", &table_id))
2848 matched = 1;
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002849#define _(a, b, v) \
2850 else if (unformat (input, #a)) \
2851 { \
2852 flow_hash_config |= v; \
2853 matched = 1; \
2854 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002855 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002856#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002857 else
2858 break;
2859 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002860
2861 if (matched == 0)
2862 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002863 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002864
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002865 rv = ip_flow_hash_set (AF_IP6, table_id, flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866 switch (rv)
2867 {
Neale Ranns227038a2017-04-21 01:07:59 -07002868 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002869 break;
2870
2871 case -1:
2872 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002873
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874 default:
2875 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2876 break;
2877 }
Dave Barach75fc8542016-10-11 16:16:02 -04002878
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879 return 0;
2880}
2881
Billy McFall0683c9c2016-10-13 08:27:31 -04002882/*?
2883 * Configure the set of IPv6 fields used by the flow hash.
2884 *
2885 * @cliexpar
2886 * @parblock
2887 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04002888 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2889 *
Billy McFall0683c9c2016-10-13 08:27:31 -04002890 * Example of display the configured flow hash:
2891 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002892 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2893 * @::/0
2894 * unicast-ip6-chain
2895 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2896 * [0] [@0]: dpo-drop ip6
2897 * fe80::/10
2898 * unicast-ip6-chain
2899 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2900 * [0] [@2]: dpo-receive
2901 * ff02::1/128
2902 * unicast-ip6-chain
2903 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2904 * [0] [@2]: dpo-receive
2905 * ff02::2/128
2906 * unicast-ip6-chain
2907 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2908 * [0] [@2]: dpo-receive
2909 * ff02::16/128
2910 * unicast-ip6-chain
2911 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2912 * [0] [@2]: dpo-receive
2913 * ff02::1:ff00:0/104
2914 * unicast-ip6-chain
2915 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2916 * [0] [@2]: dpo-receive
2917 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2918 * @::/0
2919 * unicast-ip6-chain
2920 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2921 * [0] [@0]: dpo-drop ip6
2922 * @::a:1:1:0:4/126
2923 * unicast-ip6-chain
2924 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2925 * [0] [@4]: ipv6-glean: af_packet0
2926 * @::a:1:1:0:7/128
2927 * unicast-ip6-chain
2928 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2929 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2930 * fe80::/10
2931 * unicast-ip6-chain
2932 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2933 * [0] [@2]: dpo-receive
2934 * fe80::fe:3eff:fe3e:9222/128
2935 * unicast-ip6-chain
2936 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2937 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2938 * ff02::1/128
2939 * unicast-ip6-chain
2940 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2941 * [0] [@2]: dpo-receive
2942 * ff02::2/128
2943 * unicast-ip6-chain
2944 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2945 * [0] [@2]: dpo-receive
2946 * ff02::16/128
2947 * unicast-ip6-chain
2948 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2949 * [0] [@2]: dpo-receive
2950 * ff02::1:ff00:0/104
2951 * unicast-ip6-chain
2952 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2953 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04002954 * @cliexend
2955 * @endparblock
2956?*/
2957/* *INDENT-OFF* */
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002958VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002959 .path = "set ip6 flow-hash",
Ahmed Abdelsalamf2984bb2020-11-20 18:56:09 +00002960 .short_help = "set ip6 flow-hash table <table-id> [src] [dst] [sport] "
2961 "[dport] [proto] [reverse] [flowlabel]",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002963};
Billy McFall0683c9c2016-10-13 08:27:31 -04002964/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002965
2966static clib_error_t *
2967show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002968 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002970 ip6_main_t *im = &ip6_main;
2971 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04002973
Ed Warnickecb9cada2015-12-08 15:45:58 -07002974 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05002975 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002976 {
2977 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02002978 {
2979
2980 u32 node_index = vlib_get_node (vm,
2981 ip6_local_node.index)->
2982 next_nodes[lm->local_next_by_ip_protocol[i]];
2983 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2984 node_index);
2985 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002986 }
2987 return 0;
2988}
2989
2990
2991
Billy McFall0683c9c2016-10-13 08:27:31 -04002992/*?
2993 * Display the set of protocols handled by the local IPv6 stack.
2994 *
2995 * @cliexpar
2996 * Example of how to display local protocol table:
2997 * @cliexstart{show ip6 local}
2998 * Protocols handled by ip6_local
2999 * 17
3000 * 43
3001 * 58
3002 * 115
3003 * @cliexend
3004?*/
3005/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003006VLIB_CLI_COMMAND (show_ip6_local, static) =
3007{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008 .path = "show ip6 local",
3009 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003010 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003011};
Billy McFall0683c9c2016-10-13 08:27:31 -04003012/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003013
Damjan Marion38173502019-02-13 19:30:09 +01003014#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003015int
Mohsin Kazmi68095382021-02-10 11:26:24 +01003016vnet_set_ip6_classify_intfc (vlib_main_t *vm, u32 sw_if_index, u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003017{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003018 vnet_main_t *vnm = vnet_get_main ();
3019 vnet_interface_main_t *im = &vnm->interface_main;
3020 ip6_main_t *ipm = &ip6_main;
3021 ip_lookup_main_t *lm = &ipm->lookup_main;
3022 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003023 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024
3025 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3026 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3027
3028 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3029 return VNET_API_ERROR_NO_SUCH_ENTRY;
3030
3031 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003032 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003033
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003034 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003035
3036 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003037 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003038 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003039 .fp_len = 128,
3040 .fp_proto = FIB_PROTOCOL_IP6,
3041 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003042 };
3043 u32 fib_index;
3044
Dave Barachd7cb1b52016-12-09 09:52:16 -05003045 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3046 sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003047 if (table_index != (u32) ~ 0)
3048 {
3049 dpo_id_t dpo = DPO_INVALID;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003050 dpo_set (&dpo,
3051 DPO_CLASSIFY,
3052 DPO_PROTO_IP6,
3053 classify_dpo_create (DPO_PROTO_IP6, table_index));
Dave Barachd7cb1b52016-12-09 09:52:16 -05003054 fib_table_entry_special_dpo_add (fib_index,
3055 &pfx,
3056 FIB_SOURCE_CLASSIFY,
3057 FIB_ENTRY_FLAG_NONE, &dpo);
3058 dpo_reset (&dpo);
3059 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003060 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003061 {
3062 fib_table_entry_special_remove (fib_index,
3063 &pfx, FIB_SOURCE_CLASSIFY);
3064 }
3065 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003066
Ed Warnickecb9cada2015-12-08 15:45:58 -07003067 return 0;
3068}
Damjan Marion38173502019-02-13 19:30:09 +01003069#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070
3071static clib_error_t *
3072set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003073 unformat_input_t * input,
3074 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003075{
3076 u32 table_index = ~0;
3077 int table_index_set = 0;
3078 u32 sw_if_index = ~0;
3079 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003080
Dave Barachd7cb1b52016-12-09 09:52:16 -05003081 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3082 {
3083 if (unformat (input, "table-index %d", &table_index))
3084 table_index_set = 1;
3085 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3086 vnet_get_main (), &sw_if_index))
3087 ;
3088 else
3089 break;
3090 }
Dave Barach75fc8542016-10-11 16:16:02 -04003091
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003094
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095 if (sw_if_index == ~0)
3096 return clib_error_return (0, "interface / subif must be specified");
3097
3098 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3099
3100 switch (rv)
3101 {
3102 case 0:
3103 break;
3104
3105 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3106 return clib_error_return (0, "No such interface");
3107
3108 case VNET_API_ERROR_NO_SUCH_ENTRY:
3109 return clib_error_return (0, "No such classifier table");
3110 }
3111 return 0;
3112}
3113
Billy McFall0683c9c2016-10-13 08:27:31 -04003114/*?
3115 * Assign a classification table to an interface. The classification
3116 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3117 * commands. Once the table is create, use this command to filter packets
3118 * on an interface.
3119 *
3120 * @cliexpar
3121 * Example of how to assign a classification table to an interface:
3122 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3123?*/
3124/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003125VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3126{
3127 .path = "set ip6 classify",
3128 .short_help =
3129 "set ip6 classify intfc <interface> table-index <classify-idx>",
3130 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131};
Billy McFall0683c9c2016-10-13 08:27:31 -04003132/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003133
Dave Barachd7cb1b52016-12-09 09:52:16 -05003134/*
3135 * fd.io coding-style-patch-verification: ON
3136 *
3137 * Local Variables:
3138 * eval: (c-set-style "gnu")
3139 * End:
3140 */