blob: cd753b044b15a52995ca231cfe25333a6624dd42 [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>
Ed Warnickecb9cada2015-12-08 15:45:58 -070053
Damjan Marion38173502019-02-13 19:30:09 +010054#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -070055#include <vppinfra/bihash_template.c>
Damjan Marion38173502019-02-13 19:30:09 +010056#endif
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080057#include <vnet/ip/ip6_forward.h>
Neale Ranns7b4e52f2020-05-24 16:17:50 +000058#include <vnet/ipsec/ipsec_tun.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
Pavel Kotucek57808982017-08-02 08:20:19 +0200311 /* local0 interface doesn't support IP addressing */
312 if (sw_if_index == 0)
313 {
314 return
315 clib_error_create ("local0 interface doesn't support IP addressing");
316 }
317
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200318 if (ip6_address_is_link_local_unicast (address))
319 {
320 if (address_length != 128)
321 {
322 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
323 return
324 clib_error_create
325 ("prefix length of link-local address must be 128");
326 }
327 if (!is_del)
328 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000329 int rv;
330
Neale Rannsec40a7d2020-04-23 07:36:12 +0000331 rv = ip6_link_set_local_address (sw_if_index, address);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000332
333 if (rv)
334 {
335 vnm->api_errno = rv;
336 return clib_error_create ("address not assignable");
337 }
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200338 }
339 else
340 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000341 ll_addr = ip6_get_link_local_address (sw_if_index);
342 if (ip6_address_is_equal (ll_addr, address))
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200343 {
344 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
345 return clib_error_create ("address not deletable");
346 }
347 else
348 {
349 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
350 return clib_error_create ("address not found");
351 }
352 }
Neale Rannsec40a7d2020-04-23 07:36:12 +0000353
354 return (NULL);
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200355 }
356
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000358 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
359
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 ip6_addr_fib_init (&ip6_af, address,
361 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
362 vec_add1 (addr_fib, ip6_af);
363
Neale Ranns744902e2017-08-14 10:35:44 -0700364 /* *INDENT-OFF* */
365 if (!is_del)
366 {
367 /* When adding an address check that it does not conflict
368 with an existing address on any interface in this table. */
369 ip_interface_address_t *ia;
370 vnet_sw_interface_t *sif;
371
372 pool_foreach(sif, vnm->interface_main.sw_interfaces,
373 ({
374 if (im->fib_index_by_sw_if_index[sw_if_index] ==
375 im->fib_index_by_sw_if_index[sif->sw_if_index])
376 {
377 foreach_ip_interface_address
378 (&im->lookup_main, ia, sif->sw_if_index,
379 0 /* honor unnumbered */ ,
380 ({
381 ip6_address_t * x =
382 ip_interface_address_get_address
383 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000384
Neale Ranns744902e2017-08-14 10:35:44 -0700385 if (ip6_destination_matches_route
386 (im, address, x, ia->address_length) ||
387 ip6_destination_matches_route (im,
388 x,
389 address,
390 address_length))
391 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500392 /* an intf may have >1 addr from the same prefix */
393 if ((sw_if_index == sif->sw_if_index) &&
394 (ia->address_length == address_length) &&
395 !ip6_address_is_equal (x, address))
396 continue;
397
Neale Ranns59f71132020-04-08 12:19:38 +0000398 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
399 /* if the address we're comparing against is stale
400 * then the CP has not added this one back yet, maybe
401 * it never will, so we have to assume it won't and
402 * ignore it. if it does add it back, then it will fail
403 * because this one is now present */
404 continue;
405
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500406 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700407 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
Neale Ranns59f71132020-04-08 12:19:38 +0000408 error = clib_error_create
Neale Ranns744902e2017-08-14 10:35:44 -0700409 ("failed to add %U which conflicts with %U for interface %U",
410 format_ip6_address_and_length, address,
411 address_length,
412 format_ip6_address_and_length, x,
413 ia->address_length,
414 format_vnet_sw_if_index_name, vnm,
415 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000416 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700417 }
418 }));
419 }
420 }));
421 }
422 /* *INDENT-ON* */
423
Neale Ranns59f71132020-04-08 12:19:38 +0000424 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425
Neale Ranns59f71132020-04-08 12:19:38 +0000426 if (is_del)
427 {
428 if (~0 == if_address_index)
429 {
430 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
431 error = clib_error_create ("%U not found for interface %U",
432 lm->format_address_and_length,
433 addr_fib, address_length,
434 format_vnet_sw_if_index_name, vnm,
435 sw_if_index);
436 goto done;
437 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700438
yedgdbd366b2020-05-14 10:51:53 +0800439 error = ip_interface_address_del (lm, vnm, if_address_index, addr_fib,
440 address_length, sw_if_index);
441 if (error)
442 goto done;
Neale Ranns59f71132020-04-08 12:19:38 +0000443 }
444 else
445 {
446 if (~0 != if_address_index)
447 {
448 ip_interface_address_t *ia;
449
450 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
451
452 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
453 {
454 if (ia->sw_if_index == sw_if_index)
455 {
456 /* re-adding an address during the replace action.
457 * consdier this the update. clear the flag and
458 * we're done */
459 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
460 goto done;
461 }
462 else
463 {
464 /* The prefix is moving from one interface to another.
465 * delete the stale and add the new */
466 ip6_add_del_interface_address (vm,
467 ia->sw_if_index,
468 address, address_length, 1);
469 ia = NULL;
470 error = ip_interface_address_add (lm, sw_if_index,
471 addr_fib, address_length,
472 &if_address_index);
473 }
474 }
475 else
476 {
477 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
478 error = clib_error_create
479 ("Prefix %U already found on interface %U",
480 lm->format_address_and_length, addr_fib, address_length,
481 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
482 }
483 }
484 else
485 error = ip_interface_address_add (lm, sw_if_index,
486 addr_fib, address_length,
487 &if_address_index);
488 }
489
490 if (error)
491 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492
Dave Barachd7cb1b52016-12-09 09:52:16 -0500493 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000494 if (!is_del)
Neale Rannsec40a7d2020-04-23 07:36:12 +0000495 ip6_link_enable (sw_if_index, NULL);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000496
Neale Ranns1ff3c152019-10-07 22:40:54 -0700497 /* intf addr routes are added/deleted on admin up/down */
498 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
499 {
500 if (is_del)
501 ip6_del_interface_routes (sw_if_index,
502 im, ip6_af.fib_index, address,
503 address_length);
504 else
505 ip6_add_interface_routes (vnm, sw_if_index,
506 im, ip6_af.fib_index,
507 pool_elt_at_index (lm->if_address_pool,
508 if_address_index));
509 }
Neale Ranns59f71132020-04-08 12:19:38 +0000510
511 ip6_add_del_interface_address_callback_t *cb;
512 vec_foreach (cb, im->add_del_interface_address_callbacks)
513 cb->function (im, cb->function_opaque, sw_if_index,
514 address, address_length, if_address_index, is_del);
515
Neale Rannscbe25aa2019-09-30 10:53:31 +0000516 if (is_del)
517 ip6_link_disable (sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
Dave Barachd7cb1b52016-12-09 09:52:16 -0500519done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520 vec_free (addr_fib);
521 return error;
522}
523
Damjan Marion38173502019-02-13 19:30:09 +0100524#endif
525
526static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500527ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529 ip6_main_t *im = &ip6_main;
530 ip_interface_address_t *ia;
531 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 u32 is_admin_up, fib_index;
533
534 /* Fill in lookup tables with default table (0). */
535 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
536
Dave Barachd7cb1b52016-12-09 09:52:16 -0500537 vec_validate_init_empty (im->
538 lookup_main.if_address_pool_index_by_sw_if_index,
539 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540
541 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
542
543 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
544
Dave Barachd7cb1b52016-12-09 09:52:16 -0500545 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400546 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 0 /* honor unnumbered */,
548 ({
549 a = ip_interface_address_get_address (&im->lookup_main, ia);
550 if (is_admin_up)
551 ip6_add_interface_routes (vnm, sw_if_index,
552 im, fib_index,
553 ia);
554 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500555 ip6_del_interface_routes (sw_if_index, im, fib_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556 a, ia->address_length);
557 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500558 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559
560 return 0;
561}
562
563VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
564
Dave Barachd6534602016-06-14 18:38:02 -0400565/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500566/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100567VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
568{
569 .arc_name = "ip6-unicast",
570 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500571 .last_in_arc = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100572 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
573};
574
Dave Barachd7cb1b52016-12-09 09:52:16 -0500575VNET_FEATURE_INIT (ip6_flow_classify, static) =
576{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100577 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700578 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100579 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700580};
581
Dave Barachd7cb1b52016-12-09 09:52:16 -0500582VNET_FEATURE_INIT (ip6_inacl, static) =
583{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100584 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400585 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100586 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400587};
588
Dave Barachd7cb1b52016-12-09 09:52:16 -0500589VNET_FEATURE_INIT (ip6_policer_classify, static) =
590{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100591 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700592 .node_name = "ip6-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100593 .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700594};
595
Dave Barachd7cb1b52016-12-09 09:52:16 -0500596VNET_FEATURE_INIT (ip6_ipsec, static) =
597{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100598 .arc_name = "ip6-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100599 .node_name = "ipsec6-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100600 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400601};
602
Dave Barachd7cb1b52016-12-09 09:52:16 -0500603VNET_FEATURE_INIT (ip6_l2tp, static) =
604{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100605 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400606 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100607 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400608};
609
Dave Barachd7cb1b52016-12-09 09:52:16 -0500610VNET_FEATURE_INIT (ip6_vpath, static) =
611{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100612 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400613 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500614 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
615};
616
617VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
618{
619 .arc_name = "ip6-unicast",
620 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100621 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400622};
623
Neale Ranns8269d3d2018-01-30 09:02:20 -0800624VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500625{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100626 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800627 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400628 .runs_before = VNET_FEATURES ("ip6-lookup"),
629};
630
631VNET_FEATURE_INIT (ip6_lookup, static) =
632{
633 .arc_name = "ip6-unicast",
634 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636};
637
Dave Barachd6534602016-06-14 18:38:02 -0400638/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100639VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
640{
641 .arc_name = "ip6-multicast",
642 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500643 .last_in_arc = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100644 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
645};
646
647VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
648 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400649 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000650 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400651};
652
Neale Ranns8269d3d2018-01-30 09:02:20 -0800653VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100654 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800655 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400656 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
657};
658
659VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
660 .arc_name = "ip6-multicast",
661 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100663};
Dave Barach5331c722016-08-17 11:54:30 -0400664
665/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100666VNET_FEATURE_ARC_INIT (ip6_output, static) =
667{
668 .arc_name = "ip6-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800669 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500670 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100671 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400672};
673
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100674VNET_FEATURE_INIT (ip6_outacl, static) = {
675 .arc_name = "ip6-output",
676 .node_name = "ip6-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100677 .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100678};
679
Matus Fabian08a6f012016-11-15 06:08:51 -0800680VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
681 .arc_name = "ip6-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100682 .node_name = "ipsec6-output-feature",
Matus Fabian08a6f012016-11-15 06:08:51 -0800683 .runs_before = VNET_FEATURES ("interface-output"),
684};
685
Damjan Marion8b3191e2016-11-09 19:54:20 +0100686VNET_FEATURE_INIT (ip6_interface_output, static) = {
687 .arc_name = "ip6-output",
688 .node_name = "interface-output",
689 .runs_before = 0, /* not before any other features */
690};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500691/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400692
Damjan Marion38173502019-02-13 19:30:09 +0100693static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500694ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700696 ip6_main_t *im = &ip6_main;
697
698 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
699 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
700
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200701 if (!is_add)
702 {
703 /* Ensure that IPv6 is disabled */
704 ip6_main_t *im6 = &ip6_main;
705 ip_lookup_main_t *lm6 = &im6->lookup_main;
706 ip_interface_address_t *ia = 0;
707 ip6_address_t *address;
708 vlib_main_t *vm = vlib_get_main ();
709
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700710 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200711 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700712 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200713 ({
714 address = ip_interface_address_get_address (lm6, ia);
715 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
716 }));
717 /* *INDENT-ON* */
718 ip6_mfib_interface_enable_disable (sw_if_index, 0);
719 }
720
Neale Ranns8269d3d2018-01-30 09:02:20 -0800721 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723
Neale Ranns8269d3d2018-01-30 09:02:20 -0800724 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
725 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 return /* no error */ 0;
728}
729
730VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
731
Damjan Marion38173502019-02-13 19:30:09 +0100732VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
733 vlib_node_runtime_t * node,
734 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200735{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100736 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200737}
738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100740
Dave Barachd7cb1b52016-12-09 09:52:16 -0500741/* *INDENT-OFF* */
742VLIB_REGISTER_NODE (ip6_lookup_node) =
743{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 .name = "ip6-lookup",
745 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100746 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200747 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200748 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700749};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751
Damjan Marion38173502019-02-13 19:30:09 +0100752VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
753 vlib_node_runtime_t * node,
754 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200755{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400757 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200758 u32 thread_index = vm->thread_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500759 ip6_main_t *im = &ip6_main;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400760 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
761 u16 nexts[VLIB_FRAME_SIZE], *next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100762
763 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400764 n_left = frame->n_vectors;
765 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100766
Neale Ranns3ce72b22019-05-27 08:21:32 -0400767 vlib_get_buffers (vm, from, bufs, n_left);
768
769 while (n_left >= 4)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100770 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400771 const load_balance_t *lb0, *lb1;
772 const ip6_header_t *ip0, *ip1;
773 u32 lbi0, hc0, lbi1, hc1;
774 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100775
Neale Ranns3ce72b22019-05-27 08:21:32 -0400776 /* Prefetch next iteration. */
777 {
778 vlib_prefetch_buffer_header (b[2], STORE);
779 vlib_prefetch_buffer_header (b[3], STORE);
Dave Barach75fc8542016-10-11 16:16:02 -0400780
Neale Ranns3ce72b22019-05-27 08:21:32 -0400781 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
782 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
783 }
784
785 ip0 = vlib_buffer_get_current (b[0]);
786 ip1 = vlib_buffer_get_current (b[1]);
787 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
788 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
789
790 lb0 = load_balance_get (lbi0);
791 lb1 = load_balance_get (lbi1);
792
793 /*
794 * this node is for via FIBs we can re-use the hash value from the
795 * to node if present.
796 * We don't want to use the same hash value at each level in the recursion
797 * graph as that would lead to polarisation
798 */
799 hc0 = hc1 = 0;
800
801 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400803 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500804 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400805 hc0 = vnet_buffer (b[0])->ip.flow_hash =
806 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700807 }
808 else
809 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400810 hc0 = vnet_buffer (b[0])->ip.flow_hash =
811 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400813 dpo0 = load_balance_get_fwd_bucket
814 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
815 }
816 else
817 {
818 dpo0 = load_balance_get_bucket_i (lb0, 0);
819 }
820 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
821 {
822 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400824 hc1 = vnet_buffer (b[1])->ip.flow_hash =
825 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700827 else
828 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400829 hc1 = vnet_buffer (b[1])->ip.flow_hash =
830 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700831 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400832 dpo1 = load_balance_get_fwd_bucket
833 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
834 }
835 else
836 {
837 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500838 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000839
Neale Ranns3ce72b22019-05-27 08:21:32 -0400840 next[0] = dpo0->dpoi_next_node;
841 next[1] = dpo1->dpoi_next_node;
842
843 /* Only process the HBH Option Header if explicitly configured to do so */
844 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400846 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
847 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
848 }
849 /* Only process the HBH Option Header if explicitly configured to do so */
850 if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
851 {
852 next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
853 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500854 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100855
Neale Ranns3ce72b22019-05-27 08:21:32 -0400856 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
857 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
858
859 vlib_increment_combined_counter
860 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
861 vlib_increment_combined_counter
862 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
863
864 b += 2;
865 next += 2;
866 n_left -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100867 }
868
Neale Ranns3ce72b22019-05-27 08:21:32 -0400869 while (n_left > 0)
870 {
871 const load_balance_t *lb0;
872 const ip6_header_t *ip0;
873 const dpo_id_t *dpo0;
874 u32 lbi0, hc0;
875
876 ip0 = vlib_buffer_get_current (b[0]);
877 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
878
879 lb0 = load_balance_get (lbi0);
880
881 hc0 = 0;
882 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
883 {
884 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
885 {
886 hc0 = vnet_buffer (b[0])->ip.flow_hash =
887 vnet_buffer (b[0])->ip.flow_hash >> 1;
888 }
889 else
890 {
891 hc0 = vnet_buffer (b[0])->ip.flow_hash =
892 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
893 }
894 dpo0 = load_balance_get_fwd_bucket
895 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
896 }
897 else
898 {
899 dpo0 = load_balance_get_bucket_i (lb0, 0);
900 }
901
902 next[0] = dpo0->dpoi_next_node;
903 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
904
905 /* Only process the HBH Option Header if explicitly configured to do so */
906 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
907 {
908 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
909 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
910 }
911
912 vlib_increment_combined_counter
913 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
914
915 b += 1;
916 next += 1;
917 n_left -= 1;
918 }
919
920 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
921
Neale Rannsa71844f2018-11-08 07:31:36 -0800922 if (node->flags & VLIB_NODE_FLAG_TRACE)
923 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
924
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100925 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200926}
927
Dave Barachd7cb1b52016-12-09 09:52:16 -0500928/* *INDENT-OFF* */
929VLIB_REGISTER_NODE (ip6_load_balance_node) =
930{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100931 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200932 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200933 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100934 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200935};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500936/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200937
Dave Barachd7cb1b52016-12-09 09:52:16 -0500938typedef struct
939{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 /* Adjacency taken. */
941 u32 adj_index;
942 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500943 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944
945 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946 u8 packet_data[128 - 1 * sizeof (u32)];
947}
948ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949
Damjan Marion38173502019-02-13 19:30:09 +0100950#ifndef CLIB_MARCH_VARIANT
John Lo2b81eb82017-01-30 13:12:10 -0500951u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100954 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
955 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200957 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100958
Neale Rannsdc617b82020-08-20 08:22:56 +0000959 s = format (s, "%Ufib:%d adj:%d flow:%d",
960 format_white_space, indent,
961 t->fib_index, t->adj_index, t->flow_hash);
962 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500963 format_white_space, indent,
964 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100965 return s;
966}
Damjan Marion38173502019-02-13 19:30:09 +0100967#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100968
Dave Barachd7cb1b52016-12-09 09:52:16 -0500969static u8 *
970format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100971{
972 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
973 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200975 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976
John Loac8146c2016-09-27 17:44:02 -0400977 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500978 t->fib_index, t->adj_index, t->flow_hash);
979 s = format (s, "\n%U%U",
980 format_white_space, indent,
981 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100982 return s;
983}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100984
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986static u8 *
987format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100988{
989 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
990 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200992 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100994 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 t->fib_index, t->adj_index, format_ip_adjacency,
996 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100997 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998 format_white_space, indent,
999 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001000 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001 return s;
1002}
1003
1004/* Common trace function for all ip6-forward next nodes. */
Damjan Marion38173502019-02-13 19:30:09 +01001005#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006void
1007ip6_forward_next_trace (vlib_main_t * vm,
1008 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001010{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011 u32 *from, n_left;
1012 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013
1014 n_left = frame->n_vectors;
1015 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001016
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017 while (n_left >= 4)
1018 {
1019 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020 vlib_buffer_t *b0, *b1;
1021 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001022
1023 /* Prefetch next iteration. */
1024 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1025 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1026
1027 bi0 = from[0];
1028 bi1 = from[1];
1029
1030 b0 = vlib_get_buffer (vm, bi0);
1031 b1 = vlib_get_buffer (vm, bi1);
1032
1033 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1034 {
1035 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1036 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001037 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1038 t0->fib_index =
1039 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1040 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1041 vec_elt (im->fib_index_by_sw_if_index,
1042 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001043
Dave Barach178cf492018-11-13 16:34:13 -05001044 clib_memcpy_fast (t0->packet_data,
1045 vlib_buffer_get_current (b0),
1046 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 }
1048 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1049 {
1050 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1051 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1053 t1->fib_index =
1054 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1055 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1056 vec_elt (im->fib_index_by_sw_if_index,
1057 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001058
Dave Barach178cf492018-11-13 16:34:13 -05001059 clib_memcpy_fast (t1->packet_data,
1060 vlib_buffer_get_current (b1),
1061 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
1063 from += 2;
1064 n_left -= 2;
1065 }
1066
1067 while (n_left >= 1)
1068 {
1069 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001070 vlib_buffer_t *b0;
1071 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
1073 bi0 = from[0];
1074
1075 b0 = vlib_get_buffer (vm, bi0);
1076
1077 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1078 {
1079 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1080 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001081 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1082 t0->fib_index =
1083 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1084 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1085 vec_elt (im->fib_index_by_sw_if_index,
1086 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001087
Dave Barach178cf492018-11-13 16:34:13 -05001088 clib_memcpy_fast (t0->packet_data,
1089 vlib_buffer_get_current (b0),
1090 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 }
1092 from += 1;
1093 n_left -= 1;
1094 }
1095}
1096
Ed Warnickecb9cada2015-12-08 15:45:58 -07001097/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001098u16
1099ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1100 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101{
Matthew Smith97677a22020-02-05 11:46:40 -06001102 ip_csum_t sum0 = 0;
1103 u16 payload_length, payload_length_host_byte_order;
Srikanth A02833ff2019-10-02 17:48:58 -07001104 u32 i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001105 u32 headers_size = sizeof (ip0[0]);
Dave Barachc4abafd2019-09-04 12:09:32 -04001106 u8 *data_this_buffer;
Matthew Smith97677a22020-02-05 11:46:40 -06001107 u8 next_hdr = ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110 *bogus_lengthp = 0;
1111
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
Dave Barachc4abafd2019-09-04 12:09:32 -04001113 data_this_buffer = (u8 *) (ip0 + 1);
Matthew Smith97677a22020-02-05 11:46:40 -06001114 payload_length = ip0->payload_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301116 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1117 * or UDP-Ping packets */
Matthew Smith97677a22020-02-05 11:46:40 -06001118 if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001120 u32 skip_bytes;
1121 ip6_hop_by_hop_ext_t *ext_hdr =
1122 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123
1124 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301125 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1126 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1129 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001130
Dave Barachd7cb1b52016-12-09 09:52:16 -05001131 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 headers_size += skip_bytes;
Matthew Smith97677a22020-02-05 11:46:40 -06001133
1134 /* pseudo-header adjustments:
1135 * exclude ext header bytes from payload length
1136 * use payload IP proto rather than ext header IP proto
1137 */
1138 payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1139 next_hdr = ext_hdr->next_hdr;
1140 }
1141
1142 /* Initialize checksum with ip pseudo-header. */
1143 sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1144
1145 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1146 {
1147 sum0 = ip_csum_with_carry
1148 (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1149 sum0 = ip_csum_with_carry
1150 (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001151 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152
John Lo3bc6bc22019-08-03 14:36:39 -04001153 if (p0)
Srikanth A02833ff2019-10-02 17:48:58 -07001154 return ip_calculate_l4_checksum (vm, p0, sum0,
1155 payload_length_host_byte_order,
1156 (u8 *) ip0, headers_size, NULL);
1157 else
1158 return ip_calculate_l4_checksum (vm, 0, sum0,
1159 payload_length_host_byte_order, NULL, 0,
1160 data_this_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161}
1162
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163u32
1164ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001166 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1167 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 u16 sum16;
1169 int bogus_length;
1170
1171 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1172 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1173 || ip0->protocol == IP_PROTOCOL_ICMP6
1174 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001175 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176
1177 udp0 = (void *) (ip0 + 1);
1178 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1179 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001180 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1181 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 return p0->flags;
1183 }
1184
1185 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1186
Damjan Marion213b5aa2017-07-13 21:19:27 +02001187 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1188 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189
1190 return p0->flags;
1191}
Damjan Marion38173502019-02-13 19:30:09 +01001192#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301194/**
1195 * @brief returns number of links on which src is reachable.
1196 */
1197always_inline int
1198ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1199{
1200 const load_balance_t *lb0;
1201 index_t lbi;
Florin Corasf3a3bad2018-03-28 02:18:29 -07001202 u32 fib_index;
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301203
Florin Corasf3a3bad2018-03-28 02:18:29 -07001204 fib_index = vec_elt (im->fib_index_by_sw_if_index,
1205 vnet_buffer (b)->sw_if_index[VLIB_RX]);
1206 fib_index =
1207 (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1208 fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301209
Simon Zhange7eba482019-08-25 15:30:45 +08001210 lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301211 lb0 = load_balance_get (lbi);
1212
1213 return (fib_urpf_check_size (lb0->lb_urpf));
1214}
1215
rootc9d1c5b2017-08-15 12:58:31 -04001216always_inline u8
1217ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1218 u32 * udp_offset0)
1219{
1220 u32 proto0;
1221 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1222 if (proto0 != IP_PROTOCOL_UDP)
1223 {
1224 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1225 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1226 }
1227 return proto0;
1228}
1229
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001230/* *INDENT-OFF* */
1231VNET_FEATURE_ARC_INIT (ip6_local) =
1232{
1233 .arc_name = "ip6-local",
1234 .start_nodes = VNET_FEATURES ("ip6-local"),
1235};
1236/* *INDENT-ON* */
1237
johny17478e42019-10-11 18:28:51 +02001238static_always_inline u8
1239ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
1240{
1241
1242 u16 payload_length_host_byte_order;
1243 u32 n_this_buffer, n_bytes_left;
1244 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1245 u32 headers_size = sizeof (ip0[0]);
1246 u8 *data_this_buffer;
1247
1248
1249 data_this_buffer = (u8 *) (ip0 + 1);
1250
1251 ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1252
1253 /* validate really icmp6 next */
1254
1255 if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1256 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1257 return 0;
1258
1259
1260 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1261 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1262
johnya633a432019-12-06 13:58:35 +01001263
1264 u32 n_ip_bytes_this_buffer =
1265 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1266 if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
johny17478e42019-10-11 18:28:51 +02001267 {
johnya633a432019-12-06 13:58:35 +01001268 n_this_buffer = p0->current_length > headers_size ?
1269 n_ip_bytes_this_buffer - headers_size : 0;
johny17478e42019-10-11 18:28:51 +02001270 }
1271
1272 n_bytes_left -= n_this_buffer;
1273 n_bytes_left -= p0->total_length_not_including_first_buffer;
1274
1275 if (n_bytes_left == 0)
1276 return 0;
1277 else
1278 return 1;
1279}
1280
1281
Benoît Ganne26a10192019-02-14 15:32:45 +01001282always_inline uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001283ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1284 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 ip6_main_t *im = &ip6_main;
1287 ip_lookup_main_t *lm = &im->lookup_main;
Benoît Ganne26a10192019-02-14 15:32:45 +01001288 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 vlib_node_runtime_t *error_node =
1290 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001291 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001292 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1293 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294
1295 from = vlib_frame_vector_args (frame);
1296 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001297
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 if (node->flags & VLIB_NODE_FLAG_TRACE)
1299 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1300
Benoît Ganne26a10192019-02-14 15:32:45 +01001301 vlib_get_buffers (vm, from, bufs, n_left_from);
1302 b = bufs;
1303 next = nexts;
1304
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001305 while (n_left_from > 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001307 /* Prefetch next iteration. */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001308 if (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001310 vlib_prefetch_buffer_header (b[4], STORE);
1311 vlib_prefetch_buffer_header (b[5], STORE);
1312 vlib_prefetch_buffer_data (b[2], LOAD);
1313 vlib_prefetch_buffer_data (b[3], LOAD);
Benoît Ganne26a10192019-02-14 15:32:45 +01001314 }
Dave Barach75fc8542016-10-11 16:16:02 -04001315
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001316 u8 error[2];
1317 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1318 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
Dave Barach75fc8542016-10-11 16:16:02 -04001319
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001320 ip6_header_t *ip[2];
1321 ip[0] = vlib_buffer_get_current (b[0]);
1322 ip[1] = vlib_buffer_get_current (b[1]);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001323
Benoît Ganne26a10192019-02-14 15:32:45 +01001324 if (head_of_feature_arc)
1325 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001326 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1327 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001329 u8 type[2];
1330 type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1331 type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001333 u32 flags[2];
1334 flags[0] = b[0]->flags;
1335 flags[1] = b[1]->flags;
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001336
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001337 u32 good_l4_csum[2];
1338 good_l4_csum[0] =
1339 flags[0] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1340 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1341 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1342 good_l4_csum[1] =
1343 flags[1] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
Benoît Ganne26a10192019-02-14 15:32:45 +01001344 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1345 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
Filip Tehlarb601f222017-01-02 10:22:56 +01001346
Damjan Marion34e823f2019-02-19 08:55:18 +01001347 u32 udp_offset[2] = { };
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001348 u8 is_tcp_udp[2];
1349 is_tcp_udp[0] =
1350 ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1351 is_tcp_udp[1] =
1352 ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1353 i16 len_diff[2] = { 0 };
1354 if (PREDICT_TRUE (is_tcp_udp[0]))
Shwethab78292e2016-09-13 11:51:00 +01001355 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001356 udp_header_t *udp =
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001357 (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1358 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
Benoît Ganne26a10192019-02-14 15:32:45 +01001359 && udp->checksum == 0;
1360 /* optimistically verify UDP length. */
1361 u16 ip_len, udp_len;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001362 ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
Benoît Ganne26a10192019-02-14 15:32:45 +01001363 udp_len = clib_net_to_host_u16 (udp->length);
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001364 len_diff[0] = ip_len - udp_len;
Shwethab78292e2016-09-13 11:51:00 +01001365 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001366 if (PREDICT_TRUE (is_tcp_udp[1]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001368 udp_header_t *udp =
1369 (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1370 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1371 && udp->checksum == 0;
1372 /* optimistically verify UDP length. */
1373 u16 ip_len, udp_len;
1374 ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1375 udp_len = clib_net_to_host_u16 (udp->length);
1376 len_diff[1] = ip_len - udp_len;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377 }
1378
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001379 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1380 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1381
1382 len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1383 len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1384
1385 u8 need_csum[2];
1386 need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1387 && !good_l4_csum[0]
1388 && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1389 need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1390 && !good_l4_csum[1]
1391 && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1392 if (PREDICT_FALSE (need_csum[0]))
1393 {
1394 flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1395 good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001396 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1397 }
1398 else
1399 {
1400 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1401 error[0] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001402 }
1403 if (PREDICT_FALSE (need_csum[1]))
1404 {
1405 flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1406 good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001407 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1408 }
1409 else
1410 {
1411 if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1412 error[1] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001413 }
1414
johny17478e42019-10-11 18:28:51 +02001415
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001416 error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
johny17478e42019-10-11 18:28:51 +02001417
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001418 error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
Benoît Ganne26a10192019-02-14 15:32:45 +01001420 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1421 IP6_ERROR_UDP_CHECKSUM,
1422 "Wrong IP6 errors constants");
1423 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1424 IP6_ERROR_ICMP_CHECKSUM,
1425 "Wrong IP6 errors constants");
1426
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001427 error[0] =
1428 !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1429 error[1] =
1430 !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431
1432 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001433 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001434 u8 unroutable[2];
1435 unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1436 && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1437 && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
1438 unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1439 && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1440 && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
1441 if (PREDICT_FALSE (unroutable[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001442 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001443 error[0] =
1444 !ip6_urpf_loose_check (im, b[0],
1445 ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1446 : error[0];
1447 }
1448 if (PREDICT_FALSE (unroutable[1]))
1449 {
1450 error[1] =
1451 !ip6_urpf_loose_check (im, b[1],
1452 ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1453 : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001454 }
1455
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001456 vnet_buffer (b[0])->ip.fib_index =
1457 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1458 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1459 vnet_buffer (b[0])->ip.fib_index;
1460 vnet_buffer (b[1])->ip.fib_index =
1461 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1462 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1463 vnet_buffer (b[1])->ip.fib_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001464 } /* head_of_feature_arc */
Florin Corascea194d2017-10-02 00:18:51 -07001465
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001466 next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1467 next[0] =
1468 error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1469 next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1470 next[1] =
1471 error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
Florin Corascea194d2017-10-02 00:18:51 -07001472
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001473 b[0]->error = error_node->errors[0];
1474 b[1]->error = error_node->errors[1];
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001475
Benoît Ganne26a10192019-02-14 15:32:45 +01001476 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001477 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001478 u8 ip6_unknown[2];
1479 ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1480 ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1481 if (PREDICT_TRUE (ip6_unknown[0]))
Shwethab78292e2016-09-13 11:51:00 +01001482 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001483 u32 next32 = next[0];
Benoît Ganne26a10192019-02-14 15:32:45 +01001484 vnet_feature_arc_start (arc_index,
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001485 vnet_buffer (b[0])->sw_if_index
1486 [VLIB_RX], &next32, b[0]);
1487 next[0] = next32;
1488 }
1489 if (PREDICT_TRUE (ip6_unknown[1]))
1490 {
1491 u32 next32 = next[1];
1492 vnet_feature_arc_start (arc_index,
1493 vnet_buffer (b[1])->sw_if_index
1494 [VLIB_RX], &next32, b[1]);
1495 next[1] = next32;
Shwethab78292e2016-09-13 11:51:00 +01001496 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001497 }
Dave Barach75fc8542016-10-11 16:16:02 -04001498
Benoît Ganne26a10192019-02-14 15:32:45 +01001499 /* next */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001500 b += 2;
1501 next += 2;
1502 n_left_from -= 2;
Benoît Ganne26a10192019-02-14 15:32:45 +01001503 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001504
Benoît Ganne26a10192019-02-14 15:32:45 +01001505 while (n_left_from)
1506 {
1507 u8 error;
1508 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1509
1510 ip6_header_t *ip;
1511 ip = vlib_buffer_get_current (b[0]);
1512
1513 if (head_of_feature_arc)
1514 {
1515 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1516 u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
1517
1518 u32 flags = b[0]->flags;
1519 u32 good_l4_csum =
1520 flags & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1521 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1522 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1523
1524 u32 udp_offset;
1525 i16 len_diff = 0;
1526 u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1527 if (PREDICT_TRUE (is_tcp_udp))
1528 {
1529 udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1530 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1531 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1532 && udp->checksum == 0;
1533 /* optimistically verify UDP length. */
1534 u16 ip_len, udp_len;
1535 ip_len = clib_net_to_host_u16 (ip->payload_length);
1536 udp_len = clib_net_to_host_u16 (udp->length);
1537 len_diff = ip_len - udp_len;
1538 }
1539
1540 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1541 len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1542
1543 u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN && !good_l4_csum
1544 && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1545 if (PREDICT_FALSE (need_csum))
1546 {
1547 flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1548 good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001549 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1550 }
1551 else
1552 {
1553 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1554 error = IP6_ERROR_BAD_LENGTH;
Benoît Ganne26a10192019-02-14 15:32:45 +01001555 }
1556
johny17478e42019-10-11 18:28:51 +02001557
1558
Benoît Ganne26a10192019-02-14 15:32:45 +01001559 error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
1560
1561 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1562 IP6_ERROR_UDP_CHECKSUM,
1563 "Wrong IP6 errors constants");
1564 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1565 IP6_ERROR_ICMP_CHECKSUM,
1566 "Wrong IP6 errors constants");
1567
1568 error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1569
1570 /* Drop packets from unroutable hosts. */
1571 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1572 u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1573 && type != IP_BUILTIN_PROTOCOL_ICMP
1574 && !ip6_address_is_link_local_unicast (&ip->src_address);
1575 if (PREDICT_FALSE (unroutable))
1576 {
1577 error =
1578 !ip6_urpf_loose_check (im, b[0],
1579 ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1580 error;
1581 }
1582
1583 vnet_buffer (b[0])->ip.fib_index =
1584 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1585 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1586 vnet_buffer (b[0])->ip.fib_index;
1587 } /* head_of_feature_arc */
1588
1589 next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1590 next[0] =
1591 error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1592
1593 b[0]->error = error_node->errors[0];
1594
1595 if (head_of_feature_arc)
1596 {
1597 if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1598 {
1599 u32 next32 = next[0];
1600 vnet_feature_arc_start (arc_index,
1601 vnet_buffer (b[0])->sw_if_index
1602 [VLIB_RX], &next32, b[0]);
1603 next[0] = next32;
1604 }
1605 }
1606
1607 /* next */
1608 b += 1;
1609 next += 1;
1610 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 }
1612
Benoît Ganne26a10192019-02-14 15:32:45 +01001613 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001614 return frame->n_vectors;
1615}
1616
Damjan Marion38173502019-02-13 19:30:09 +01001617VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1618 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001619{
1620 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1621}
1622
Dave Barachd7cb1b52016-12-09 09:52:16 -05001623/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001624VLIB_REGISTER_NODE (ip6_local_node) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001625{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626 .name = "ip6-local",
1627 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001628 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001629 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001630 .next_nodes =
1631 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001632 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1633 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001634 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1635 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001636 [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001637 },
1638};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001639/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001640
Damjan Marion38173502019-02-13 19:30:09 +01001641VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
1642 vlib_node_runtime_t * node,
1643 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001644{
1645 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1646}
1647
1648/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001649VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001650 .name = "ip6-local-end-of-arc",
1651 .vector_size = sizeof (u32),
1652
1653 .format_trace = format_ip6_forward_next_trace,
1654 .sibling_of = "ip6-local",
1655};
1656
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001657VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1658 .arc_name = "ip6-local",
1659 .node_name = "ip6-local-end-of-arc",
1660 .runs_before = 0, /* not before any other features */
1661};
1662/* *INDENT-ON* */
1663
Damjan Marion38173502019-02-13 19:30:09 +01001664#ifdef CLIB_MARCH_VARIANT
1665extern vlib_node_registration_t ip6_local_node;
Damjan Marion38173502019-02-13 19:30:09 +01001666#else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001667void
1668ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001669{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001670 vlib_main_t *vm = vlib_get_main ();
1671 ip6_main_t *im = &ip6_main;
1672 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001673
1674 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001675 lm->local_next_by_ip_protocol[protocol] =
1676 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677}
1678
Neale Rannsb538dd82019-05-21 06:54:54 -07001679void
1680ip6_unregister_protocol (u32 protocol)
1681{
1682 ip6_main_t *im = &ip6_main;
1683 ip_lookup_main_t *lm = &im->lookup_main;
1684
1685 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1686 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1687}
Damjan Marion38173502019-02-13 19:30:09 +01001688#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689
Dave Barachd7cb1b52016-12-09 09:52:16 -05001690typedef enum
1691{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001692 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001693 IP6_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001694 IP6_REWRITE_NEXT_FRAGMENT,
1695 IP6_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001696} ip6_rewrite_next_t;
1697
Neale Ranns889fe942017-06-01 05:43:19 -04001698/**
1699 * This bits of an IPv6 address to mask to construct a multicast
1700 * MAC address
1701 */
1702#define IP6_MCAST_ADDR_MASK 0xffffffff
1703
Ole Troanda6e11b2018-05-23 11:21:42 +02001704always_inline void
1705ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
Ole Troan313f7e22018-04-10 16:02:51 +02001706 u16 adj_packet_bytes, bool is_locally_generated,
Ole Troaneb284a12019-10-09 13:33:19 +02001707 u32 * next, u8 is_midchain, u32 * error)
Ole Troanda6e11b2018-05-23 11:21:42 +02001708{
1709 if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1710 {
Ole Troan313f7e22018-04-10 16:02:51 +02001711 if (is_locally_generated)
1712 {
1713 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02001714 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001715 (is_midchain ?
1716 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1717 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02001718 *next = IP6_REWRITE_NEXT_FRAGMENT;
Ole Troan282093f2018-09-19 12:38:51 +02001719 *error = IP6_ERROR_MTU_EXCEEDED;
Ole Troan313f7e22018-04-10 16:02:51 +02001720 }
1721 else
1722 {
1723 *error = IP6_ERROR_MTU_EXCEEDED;
1724 icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1725 adj_packet_bytes);
1726 *next = IP6_REWRITE_NEXT_ICMP_ERROR;
1727 }
Ole Troanda6e11b2018-05-23 11:21:42 +02001728 }
1729}
1730
Ed Warnickecb9cada2015-12-08 15:45:58 -07001731always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001732ip6_rewrite_inline_with_gso (vlib_main_t * vm,
1733 vlib_node_runtime_t * node,
1734 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001735 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001736{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001737 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1738 u32 *from = vlib_frame_vector_args (frame);
1739 u32 n_left_from, n_left_to_next, *to_next, next_index;
1740 vlib_node_runtime_t *error_node =
1741 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742
1743 n_left_from = frame->n_vectors;
1744 next_index = node->cached_next_index;
Damjan Marion067cd622018-07-11 12:47:43 +02001745 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001746
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747 while (n_left_from > 0)
1748 {
1749 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1750
1751 while (n_left_from >= 4 && n_left_to_next >= 2)
1752 {
Neale Ranns960eeea2019-12-02 23:28:50 +00001753 const ip_adjacency_t *adj0, *adj1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001754 vlib_buffer_t *p0, *p1;
1755 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 u32 pi0, rw_len0, next0, error0, adj_index0;
1757 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001758 u32 tx_sw_if_index0, tx_sw_if_index1;
Ole Troan313f7e22018-04-10 16:02:51 +02001759 bool is_locally_originated0, is_locally_originated1;
Dave Barach75fc8542016-10-11 16:16:02 -04001760
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 /* Prefetch next iteration. */
1762 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764
1765 p2 = vlib_get_buffer (vm, from[2]);
1766 p3 = vlib_get_buffer (vm, from[3]);
1767
1768 vlib_prefetch_buffer_header (p2, LOAD);
1769 vlib_prefetch_buffer_header (p3, LOAD);
1770
1771 CLIB_PREFETCH (p2->pre_data, 32, STORE);
1772 CLIB_PREFETCH (p3->pre_data, 32, STORE);
1773
1774 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1775 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1776 }
1777
1778 pi0 = to_next[0] = from[0];
1779 pi1 = to_next[1] = from[1];
1780
1781 from += 2;
1782 n_left_from -= 2;
1783 to_next += 2;
1784 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001785
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 p0 = vlib_get_buffer (vm, pi0);
1787 p1 = vlib_get_buffer (vm, pi1);
1788
Neale Rannsf06aea52016-11-29 06:51:37 -08001789 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1790 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792 ip0 = vlib_buffer_get_current (p0);
1793 ip1 = vlib_buffer_get_current (p1);
1794
1795 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001796 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001797
Ole Troan313f7e22018-04-10 16:02:51 +02001798 is_locally_originated0 =
1799 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1800 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001802 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803
1804 /* Input node should have reject packets with hop limit 0. */
1805 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806
1807 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001808
1809 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001810
Dave Barachd7cb1b52016-12-09 09:52:16 -05001811 /*
1812 * If the hop count drops below 1 when forwarding, generate
1813 * an ICMP response.
1814 */
1815 if (PREDICT_FALSE (hop_limit0 <= 0))
1816 {
1817 error0 = IP6_ERROR_TIME_EXPIRED;
1818 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1819 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1820 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1821 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1822 0);
1823 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001824 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001825
Ole Troan313f7e22018-04-10 16:02:51 +02001826 is_locally_originated1 =
1827 p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1828 if (PREDICT_TRUE (!is_locally_originated1))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001829 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001830 i32 hop_limit1 = ip1->hop_limit;
1831
1832 /* Input node should have reject packets with hop limit 0. */
1833 ASSERT (ip1->hop_limit > 0);
1834
1835 hop_limit1 -= 1;
1836
1837 ip1->hop_limit = hop_limit1;
1838
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839 /*
1840 * If the hop count drops below 1 when forwarding, generate
1841 * an ICMP response.
1842 */
1843 if (PREDICT_FALSE (hop_limit1 <= 0))
1844 {
1845 error1 = IP6_ERROR_TIME_EXPIRED;
1846 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1847 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1848 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1849 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1850 0);
1851 }
1852 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001853
Neale Ranns107e7d42017-04-11 09:55:19 -07001854 adj0 = adj_get (adj_index0);
1855 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857 rw_len0 = adj0[0].rewrite_header.data_bytes;
1858 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001859 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1860 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861
Neale Ranns9c6a6132017-02-21 05:33:14 -08001862 if (do_counters)
1863 {
1864 vlib_increment_combined_counter
1865 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001866 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001867 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1868 vlib_increment_combined_counter
1869 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001870 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001871 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1872 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873
1874 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001875 u16 ip0_len =
1876 clib_net_to_host_u16 (ip0->payload_length) +
1877 sizeof (ip6_header_t);
1878 u16 ip1_len =
1879 clib_net_to_host_u16 (ip1->payload_length) +
1880 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001881 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001882 ip0_len = gso_mtu_sz (p0);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001883 if (p1->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001884 ip1_len = gso_mtu_sz (p1);
1885
1886
1887
1888 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001889 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001890 is_locally_originated0, &next0, is_midchain,
1891 &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001892 ip6_mtu_check (p1, ip1_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001893 adj1[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001894 is_locally_originated1, &next1, is_midchain,
1895 &error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896
Dave Barachd7cb1b52016-12-09 09:52:16 -05001897 /* Don't adjust the buffer for hop count issue; icmp-error node
Jim Thompsonf324dec2019-04-08 03:22:21 -05001898 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001899 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1900 {
1901 p0->current_data -= rw_len0;
1902 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903
Dave Barachd7cb1b52016-12-09 09:52:16 -05001904 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1905 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1906 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001907
Neale Rannsb069a692017-03-15 12:34:25 -04001908 if (PREDICT_FALSE
1909 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001910 vnet_feature_arc_start_w_cfg_index
1911 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
1912 adj0->ia_cfg_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001913 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001914 else
1915 {
1916 p0->error = error_node->errors[error0];
1917 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001918 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1919 {
1920 p1->current_data -= rw_len1;
1921 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001922
Dave Barachd7cb1b52016-12-09 09:52:16 -05001923 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1924 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1925 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001926
Neale Rannsb069a692017-03-15 12:34:25 -04001927 if (PREDICT_FALSE
1928 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04001929 vnet_feature_arc_start_w_cfg_index
1930 (lm->output_feature_arc_index, tx_sw_if_index1, &next1, p1,
1931 adj1->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001932 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001933 else
1934 {
1935 p1->error = error_node->errors[error1];
1936 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001937
Neale Ranns25edf142019-03-22 08:12:48 +00001938 if (is_midchain)
1939 {
1940 /* before we paint on the next header, update the L4
1941 * checksums if required, since there's no offload on a tunnel */
Dave Barach1bd2c012020-04-12 08:31:39 -04001942 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001943 1 /* is_ip6 */ );
Dave Barach1bd2c012020-04-12 08:31:39 -04001944 vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03001945 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00001946
Neale Ranns4ec36c52020-03-31 09:21:29 -04001947 /* Guess we are only writing on ipv6 header. */
1948 vnet_rewrite_two_headers (adj0[0], adj1[0],
1949 ip0, ip1, sizeof (ip6_header_t));
1950 }
1951 else
1952 /* Guess we are only writing on simple Ethernet header. */
1953 vnet_rewrite_two_headers (adj0[0], adj1[0],
1954 ip0, ip1, sizeof (ethernet_header_t));
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001955
1956 if (is_midchain)
1957 {
Neale Ranns25edf142019-03-22 08:12:48 +00001958 if (adj0->sub_type.midchain.fixup_func)
1959 adj0->sub_type.midchain.fixup_func
1960 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1961 if (adj1->sub_type.midchain.fixup_func)
1962 adj1->sub_type.midchain.fixup_func
1963 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001964 }
1965 if (is_mcast)
1966 {
1967 /*
1968 * copy bytes from the IP address into the MAC rewrite
1969 */
Neale Ranns889fe942017-06-01 05:43:19 -04001970 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1971 adj0->
1972 rewrite_header.dst_mcast_offset,
1973 &ip0->dst_address.as_u32[3],
1974 (u8 *) ip0);
1975 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1976 adj1->
1977 rewrite_header.dst_mcast_offset,
1978 &ip1->dst_address.as_u32[3],
1979 (u8 *) ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001980 }
Neale Ranns5e575b12016-10-03 09:40:25 +01001981
Ed Warnickecb9cada2015-12-08 15:45:58 -07001982 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1983 to_next, n_left_to_next,
1984 pi0, pi1, next0, next1);
1985 }
1986
1987 while (n_left_from > 0 && n_left_to_next > 0)
1988 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001989 ip_adjacency_t *adj0;
1990 vlib_buffer_t *p0;
1991 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992 u32 pi0, rw_len0;
1993 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001994 u32 tx_sw_if_index0;
Ole Troan313f7e22018-04-10 16:02:51 +02001995 bool is_locally_originated0;
Dave Barach75fc8542016-10-11 16:16:02 -04001996
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997 pi0 = to_next[0] = from[0];
1998
1999 p0 = vlib_get_buffer (vm, pi0);
2000
Neale Rannsf06aea52016-11-29 06:51:37 -08002001 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002
Neale Ranns107e7d42017-04-11 09:55:19 -07002003 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002004
Ed Warnickecb9cada2015-12-08 15:45:58 -07002005 ip0 = vlib_buffer_get_current (p0);
2006
2007 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002008 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009
2010 /* Check hop limit */
Ole Troan313f7e22018-04-10 16:02:51 +02002011 is_locally_originated0 =
2012 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
2013 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002014 {
2015 i32 hop_limit0 = ip0->hop_limit;
2016
2017 ASSERT (ip0->hop_limit > 0);
2018
2019 hop_limit0 -= 1;
2020
2021 ip0->hop_limit = hop_limit0;
2022
Dave Barachd7cb1b52016-12-09 09:52:16 -05002023 if (PREDICT_FALSE (hop_limit0 <= 0))
2024 {
2025 /*
2026 * If the hop count drops below 1 when forwarding, generate
2027 * an ICMP response.
2028 */
2029 error0 = IP6_ERROR_TIME_EXPIRED;
2030 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2031 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2032 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2033 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2034 0);
2035 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002036 }
2037
Neale Ranns25edf142019-03-22 08:12:48 +00002038 if (is_midchain)
2039 {
Dave Barach1bd2c012020-04-12 08:31:39 -04002040 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
Vladimir Isaev698eb872020-05-21 16:34:17 +03002041 1 /* is_ip6 */ );
Neale Ranns25edf142019-03-22 08:12:48 +00002042
Neale Ranns4ec36c52020-03-31 09:21:29 -04002043 /* Guess we are only writing on ip6 header. */
2044 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ip6_header_t));
2045 }
2046 else
2047 /* Guess we are only writing on simple Ethernet header. */
2048 vnet_rewrite_one_header (adj0[0], ip0,
2049 sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002050
Ed Warnickecb9cada2015-12-08 15:45:58 -07002051 /* Update packet buffer attributes/set output interface. */
2052 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002053 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054
Neale Ranns9c6a6132017-02-21 05:33:14 -08002055 if (do_counters)
2056 {
2057 vlib_increment_combined_counter
2058 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002059 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002060 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2061 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062
2063 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002064 u16 ip0_len =
2065 clib_net_to_host_u16 (ip0->payload_length) +
2066 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002067 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002068 ip0_len = gso_mtu_sz (p0);
2069
2070 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02002071 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02002072 is_locally_originated0, &next0, is_midchain,
2073 &error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002074
Dave Barachd7cb1b52016-12-09 09:52:16 -05002075 /* Don't adjust the buffer for hop count issue; icmp-error node
Ole Troanda6e11b2018-05-23 11:21:42 +02002076 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002077 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2078 {
Chris Luke816f3e12016-06-14 16:24:47 -04002079 p0->current_data -= rw_len0;
2080 p0->current_length += rw_len0;
2081
Dave Barachd7cb1b52016-12-09 09:52:16 -05002082 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002083
Dave Barachd7cb1b52016-12-09 09:52:16 -05002084 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2085 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002086
Neale Rannsb069a692017-03-15 12:34:25 -04002087 if (PREDICT_FALSE
2088 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
Neale Ranns4ec36c52020-03-31 09:21:29 -04002089 vnet_feature_arc_start_w_cfg_index
2090 (lm->output_feature_arc_index, tx_sw_if_index0, &next0, p0,
2091 adj0->ia_cfg_index);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002092 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002093 else
2094 {
2095 p0->error = error_node->errors[error0];
2096 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002098 if (is_midchain)
2099 {
Neale Ranns25edf142019-03-22 08:12:48 +00002100 if (adj0->sub_type.midchain.fixup_func)
2101 adj0->sub_type.midchain.fixup_func
2102 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002103 }
2104 if (is_mcast)
2105 {
Neale Ranns889fe942017-06-01 05:43:19 -04002106 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2107 adj0->
2108 rewrite_header.dst_mcast_offset,
2109 &ip0->dst_address.as_u32[3],
2110 (u8 *) ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002111 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002112
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113 from += 1;
2114 n_left_from -= 1;
2115 to_next += 1;
2116 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002117
Ed Warnickecb9cada2015-12-08 15:45:58 -07002118 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2119 to_next, n_left_to_next,
2120 pi0, next0);
2121 }
2122
2123 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2124 }
2125
2126 /* Need to do trace after rewrites to pick up new packet data. */
2127 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002128 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002129
2130 return frame->n_vectors;
2131}
2132
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002133always_inline uword
2134ip6_rewrite_inline (vlib_main_t * vm,
2135 vlib_node_runtime_t * node,
2136 vlib_frame_t * frame,
2137 int do_counters, int is_midchain, int is_mcast)
2138{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002139 return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2140 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002141}
2142
Damjan Marion38173502019-02-13 19:30:09 +01002143VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
2144 vlib_node_runtime_t * node,
2145 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002146{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002147 if (adj_are_counters_enabled ())
2148 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2149 else
2150 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002151}
2152
Damjan Marion38173502019-02-13 19:30:09 +01002153VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
2154 vlib_node_runtime_t * node,
2155 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002156{
2157 if (adj_are_counters_enabled ())
2158 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2159 else
2160 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2161}
2162
Damjan Marion38173502019-02-13 19:30:09 +01002163VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
2164 vlib_node_runtime_t * node,
2165 vlib_frame_t * frame)
Neale Ranns32e1c012016-11-22 17:07:28 +00002166{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002167 if (adj_are_counters_enabled ())
2168 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2169 else
2170 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002171}
2172
Damjan Marion38173502019-02-13 19:30:09 +01002173VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
2174 vlib_node_runtime_t * node,
2175 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002176{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002177 if (adj_are_counters_enabled ())
2178 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2179 else
2180 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002181}
2182
Damjan Marion38173502019-02-13 19:30:09 +01002183VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
2184 vlib_node_runtime_t * node,
2185 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002186{
2187 if (adj_are_counters_enabled ())
2188 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2189 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002190 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002191}
2192
Dave Barachd7cb1b52016-12-09 09:52:16 -05002193/* *INDENT-OFF* */
2194VLIB_REGISTER_NODE (ip6_midchain_node) =
2195{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002196 .name = "ip6-midchain",
2197 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002198 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002199 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002200 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002201
Dave Barachd7cb1b52016-12-09 09:52:16 -05002202VLIB_REGISTER_NODE (ip6_rewrite_node) =
2203{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204 .name = "ip6-rewrite",
2205 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002206 .format_trace = format_ip6_rewrite_trace,
Ole Troan313f7e22018-04-10 16:02:51 +02002207 .n_next_nodes = IP6_REWRITE_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002208 .next_nodes =
2209 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002210 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002211 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002212 [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002213 },
2214};
2215
Neale Ranns1855b8e2018-07-11 10:31:26 -07002216VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002217 .name = "ip6-rewrite-bcast",
2218 .vector_size = sizeof (u32),
2219
2220 .format_trace = format_ip6_rewrite_trace,
2221 .sibling_of = "ip6-rewrite",
2222};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002223
Neale Ranns32e1c012016-11-22 17:07:28 +00002224VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2225{
Neale Ranns32e1c012016-11-22 17:07:28 +00002226 .name = "ip6-rewrite-mcast",
2227 .vector_size = sizeof (u32),
2228 .format_trace = format_ip6_rewrite_trace,
2229 .sibling_of = "ip6-rewrite",
2230};
Neale Ranns32e1c012016-11-22 17:07:28 +00002231
Neale Ranns32e1c012016-11-22 17:07:28 +00002232
Damjan Marion38173502019-02-13 19:30:09 +01002233VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002234{
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002235 .name = "ip6-mcast-midchain",
2236 .vector_size = sizeof (u32),
2237 .format_trace = format_ip6_rewrite_trace,
2238 .sibling_of = "ip6-rewrite",
2239};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002240
Neale Ranns1855b8e2018-07-11 10:31:26 -07002241/* *INDENT-ON* */
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002242
Ole Troan944f5482016-05-24 11:56:58 +02002243/*
2244 * Hop-by-Hop handling
2245 */
Benoît Ganne47727c02019-02-12 13:35:08 +01002246#ifndef CLIB_MARCH_VARIANT
Ole Troan944f5482016-05-24 11:56:58 +02002247ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01002248#endif /* CLIB_MARCH_VARIANT */
Ole Troan944f5482016-05-24 11:56:58 +02002249
2250#define foreach_ip6_hop_by_hop_error \
2251_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2252_(FORMAT, "incorrectly formatted hop-by-hop options") \
2253_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2254
Neale Ranns32e1c012016-11-22 17:07:28 +00002255/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256typedef enum
2257{
Ole Troan944f5482016-05-24 11:56:58 +02002258#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2259 foreach_ip6_hop_by_hop_error
2260#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002261 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002262} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002263/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002264
2265/*
2266 * Primary h-b-h handler trace support
2267 * We work pretty hard on the problem for obvious reasons
2268 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002269typedef struct
2270{
Ole Troan944f5482016-05-24 11:56:58 +02002271 u32 next_index;
2272 u32 trace_len;
2273 u8 option_data[256];
2274} ip6_hop_by_hop_trace_t;
2275
Benoît Ganne47727c02019-02-12 13:35:08 +01002276extern vlib_node_registration_t ip6_hop_by_hop_node;
Ole Troan944f5482016-05-24 11:56:58 +02002277
Dave Barachd7cb1b52016-12-09 09:52:16 -05002278static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002279#define _(sym,string) string,
2280 foreach_ip6_hop_by_hop_error
2281#undef _
2282};
2283
Damjan Marion38173502019-02-13 19:30:09 +01002284#ifndef CLIB_MARCH_VARIANT
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302285u8 *
2286format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2287{
2288 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2289 int total_len = va_arg (*args, int);
2290 ip6_hop_by_hop_option_t *opt0, *limit0;
2291 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2292 u8 type0;
2293
2294 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2295 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2296
2297 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2298 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2299
2300 while (opt0 < limit0)
2301 {
2302 type0 = opt0->type;
2303 switch (type0)
2304 {
2305 case 0: /* Pad, just stop */
2306 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2307 break;
2308
2309 default:
2310 if (hm->trace[type0])
2311 {
2312 s = (*hm->trace[type0]) (s, opt0);
2313 }
2314 else
2315 {
2316 s =
2317 format (s, "\n unrecognized option %d length %d", type0,
2318 opt0->length);
2319 }
2320 opt0 =
2321 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2322 sizeof (ip6_hop_by_hop_option_t));
2323 break;
2324 }
2325 }
2326 return s;
2327}
Damjan Marion38173502019-02-13 19:30:09 +01002328#endif
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302329
Ole Troan944f5482016-05-24 11:56:58 +02002330static u8 *
2331format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2332{
2333 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2334 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002335 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002336 ip6_hop_by_hop_header_t *hbh0;
2337 ip6_hop_by_hop_option_t *opt0, *limit0;
2338 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2339
2340 u8 type0;
2341
Dave Barachd7cb1b52016-12-09 09:52:16 -05002342 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002343
2344 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002345 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002346
Dave Barachd7cb1b52016-12-09 09:52:16 -05002347 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2348 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002349
Dave Barachd7cb1b52016-12-09 09:52:16 -05002350 while (opt0 < limit0)
2351 {
2352 type0 = opt0->type;
2353 switch (type0)
2354 {
2355 case 0: /* Pad, just stop */
2356 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2357 break;
Ole Troan944f5482016-05-24 11:56:58 +02002358
Dave Barachd7cb1b52016-12-09 09:52:16 -05002359 default:
2360 if (hm->trace[type0])
2361 {
2362 s = (*hm->trace[type0]) (s, opt0);
2363 }
2364 else
2365 {
2366 s =
2367 format (s, "\n unrecognized option %d length %d", type0,
2368 opt0->length);
2369 }
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
Damjan Marion38173502019-02-13 19:30:09 +01002835#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002836int
2837vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838{
Neale Ranns107e7d42017-04-11 09:55:19 -07002839 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002840
Neale Ranns107e7d42017-04-11 09:55:19 -07002841 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842
Neale Ranns107e7d42017-04-11 09:55:19 -07002843 if (~0 == fib_index)
2844 return VNET_API_ERROR_NO_SUCH_FIB;
2845
Neale Ranns227038a2017-04-21 01:07:59 -07002846 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
2847 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002848
Neale Ranns227038a2017-04-21 01:07:59 -07002849 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002850}
Damjan Marion38173502019-02-13 19:30:09 +01002851#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002852
2853static clib_error_t *
2854set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002855 unformat_input_t * input,
2856 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002857{
2858 int matched = 0;
2859 u32 table_id = 0;
2860 u32 flow_hash_config = 0;
2861 int rv;
2862
Dave Barachd7cb1b52016-12-09 09:52:16 -05002863 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2864 {
2865 if (unformat (input, "table %d", &table_id))
2866 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002867#define _(a,v) \
2868 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002869 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002870#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002871 else
2872 break;
2873 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874
2875 if (matched == 0)
2876 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002877 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002878
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
2880 switch (rv)
2881 {
Neale Ranns227038a2017-04-21 01:07:59 -07002882 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002883 break;
2884
2885 case -1:
2886 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002887
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888 default:
2889 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2890 break;
2891 }
Dave Barach75fc8542016-10-11 16:16:02 -04002892
Ed Warnickecb9cada2015-12-08 15:45:58 -07002893 return 0;
2894}
2895
Billy McFall0683c9c2016-10-13 08:27:31 -04002896/*?
2897 * Configure the set of IPv6 fields used by the flow hash.
2898 *
2899 * @cliexpar
2900 * @parblock
2901 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04002902 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2903 *
Billy McFall0683c9c2016-10-13 08:27:31 -04002904 * Example of display the configured flow hash:
2905 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002906 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2907 * @::/0
2908 * unicast-ip6-chain
2909 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2910 * [0] [@0]: dpo-drop ip6
2911 * fe80::/10
2912 * unicast-ip6-chain
2913 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2914 * [0] [@2]: dpo-receive
2915 * ff02::1/128
2916 * unicast-ip6-chain
2917 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2918 * [0] [@2]: dpo-receive
2919 * ff02::2/128
2920 * unicast-ip6-chain
2921 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2922 * [0] [@2]: dpo-receive
2923 * ff02::16/128
2924 * unicast-ip6-chain
2925 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2926 * [0] [@2]: dpo-receive
2927 * ff02::1:ff00:0/104
2928 * unicast-ip6-chain
2929 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2930 * [0] [@2]: dpo-receive
2931 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2932 * @::/0
2933 * unicast-ip6-chain
2934 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2935 * [0] [@0]: dpo-drop ip6
2936 * @::a:1:1:0:4/126
2937 * unicast-ip6-chain
2938 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2939 * [0] [@4]: ipv6-glean: af_packet0
2940 * @::a:1:1:0:7/128
2941 * unicast-ip6-chain
2942 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2943 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2944 * fe80::/10
2945 * unicast-ip6-chain
2946 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2947 * [0] [@2]: dpo-receive
2948 * fe80::fe:3eff:fe3e:9222/128
2949 * unicast-ip6-chain
2950 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2951 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2952 * ff02::1/128
2953 * unicast-ip6-chain
2954 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2955 * [0] [@2]: dpo-receive
2956 * ff02::2/128
2957 * unicast-ip6-chain
2958 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2959 * [0] [@2]: dpo-receive
2960 * ff02::16/128
2961 * unicast-ip6-chain
2962 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2963 * [0] [@2]: dpo-receive
2964 * ff02::1:ff00:0/104
2965 * unicast-ip6-chain
2966 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2967 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04002968 * @cliexend
2969 * @endparblock
2970?*/
2971/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002972VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
2973{
2974 .path = "set ip6 flow-hash",
2975 .short_help =
2976 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2977 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978};
Billy McFall0683c9c2016-10-13 08:27:31 -04002979/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980
2981static clib_error_t *
2982show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002983 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002984{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002985 ip6_main_t *im = &ip6_main;
2986 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04002988
Ed Warnickecb9cada2015-12-08 15:45:58 -07002989 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05002990 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991 {
2992 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02002993 {
2994
2995 u32 node_index = vlib_get_node (vm,
2996 ip6_local_node.index)->
2997 next_nodes[lm->local_next_by_ip_protocol[i]];
2998 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2999 node_index);
3000 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003001 }
3002 return 0;
3003}
3004
3005
3006
Billy McFall0683c9c2016-10-13 08:27:31 -04003007/*?
3008 * Display the set of protocols handled by the local IPv6 stack.
3009 *
3010 * @cliexpar
3011 * Example of how to display local protocol table:
3012 * @cliexstart{show ip6 local}
3013 * Protocols handled by ip6_local
3014 * 17
3015 * 43
3016 * 58
3017 * 115
3018 * @cliexend
3019?*/
3020/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021VLIB_CLI_COMMAND (show_ip6_local, static) =
3022{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023 .path = "show ip6 local",
3024 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003025 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003026};
Billy McFall0683c9c2016-10-13 08:27:31 -04003027/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003028
Damjan Marion38173502019-02-13 19:30:09 +01003029#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003030int
3031vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3032 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003033{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003034 vnet_main_t *vnm = vnet_get_main ();
3035 vnet_interface_main_t *im = &vnm->interface_main;
3036 ip6_main_t *ipm = &ip6_main;
3037 ip_lookup_main_t *lm = &ipm->lookup_main;
3038 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003039 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003040
3041 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3042 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3043
3044 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3045 return VNET_API_ERROR_NO_SUCH_ENTRY;
3046
3047 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003048 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003049
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003050 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003051
3052 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003053 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003054 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003055 .fp_len = 128,
3056 .fp_proto = FIB_PROTOCOL_IP6,
3057 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003058 };
3059 u32 fib_index;
3060
Dave Barachd7cb1b52016-12-09 09:52:16 -05003061 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3062 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003063
3064
Dave Barachd7cb1b52016-12-09 09:52:16 -05003065 if (table_index != (u32) ~ 0)
3066 {
3067 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003068
Dave Barachd7cb1b52016-12-09 09:52:16 -05003069 dpo_set (&dpo,
3070 DPO_CLASSIFY,
3071 DPO_PROTO_IP6,
3072 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003073
Dave Barachd7cb1b52016-12-09 09:52:16 -05003074 fib_table_entry_special_dpo_add (fib_index,
3075 &pfx,
3076 FIB_SOURCE_CLASSIFY,
3077 FIB_ENTRY_FLAG_NONE, &dpo);
3078 dpo_reset (&dpo);
3079 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003080 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003081 {
3082 fib_table_entry_special_remove (fib_index,
3083 &pfx, FIB_SOURCE_CLASSIFY);
3084 }
3085 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003086
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087 return 0;
3088}
Damjan Marion38173502019-02-13 19:30:09 +01003089#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003090
3091static clib_error_t *
3092set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093 unformat_input_t * input,
3094 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095{
3096 u32 table_index = ~0;
3097 int table_index_set = 0;
3098 u32 sw_if_index = ~0;
3099 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003100
Dave Barachd7cb1b52016-12-09 09:52:16 -05003101 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3102 {
3103 if (unformat (input, "table-index %d", &table_index))
3104 table_index_set = 1;
3105 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3106 vnet_get_main (), &sw_if_index))
3107 ;
3108 else
3109 break;
3110 }
Dave Barach75fc8542016-10-11 16:16:02 -04003111
Ed Warnickecb9cada2015-12-08 15:45:58 -07003112 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003113 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003114
Ed Warnickecb9cada2015-12-08 15:45:58 -07003115 if (sw_if_index == ~0)
3116 return clib_error_return (0, "interface / subif must be specified");
3117
3118 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3119
3120 switch (rv)
3121 {
3122 case 0:
3123 break;
3124
3125 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3126 return clib_error_return (0, "No such interface");
3127
3128 case VNET_API_ERROR_NO_SUCH_ENTRY:
3129 return clib_error_return (0, "No such classifier table");
3130 }
3131 return 0;
3132}
3133
Billy McFall0683c9c2016-10-13 08:27:31 -04003134/*?
3135 * Assign a classification table to an interface. The classification
3136 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3137 * commands. Once the table is create, use this command to filter packets
3138 * on an interface.
3139 *
3140 * @cliexpar
3141 * Example of how to assign a classification table to an interface:
3142 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3143?*/
3144/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003145VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3146{
3147 .path = "set ip6 classify",
3148 .short_help =
3149 "set ip6 classify intfc <interface> table-index <classify-idx>",
3150 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003151};
Billy McFall0683c9c2016-10-13 08:27:31 -04003152/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003153
Dave Barachd7cb1b52016-12-09 09:52:16 -05003154/*
3155 * fd.io coding-style-patch-verification: ON
3156 *
3157 * Local Variables:
3158 * eval: (c-set-style "gnu")
3159 * End:
3160 */