blob: 0a455351ad2479720704fd0735f8810abcf37dd7 [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 Ranns25edf142019-03-22 08:12:48 +000058#include <vnet/interface_output.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053060/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
61#define OI_DECAP 0x80000000
62
Ed Warnickecb9cada2015-12-08 15:45:58 -070063static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -050064ip6_add_interface_prefix_routes (ip6_main_t * im,
65 u32 sw_if_index,
66 u32 fib_index,
67 ip6_address_t * address, u32 address_length)
68{
69 ip_lookup_main_t *lm = &im->lookup_main;
70 ip_interface_prefix_t *if_prefix;
71
Neale Ranns1ff3c152019-10-07 22:40:54 -070072 /* *INDENT-OFF* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -050073 ip_interface_prefix_key_t key = {
74 .prefix = {
Neale Ranns1ff3c152019-10-07 22:40:54 -070075 .fp_len = address_length,
76 .fp_proto = FIB_PROTOCOL_IP6,
77 .fp_addr.ip6 = {
78 .as_u64 = {
79 address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
80 address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
81 },
82 },
83 },
Matthew Smith6c92f5b2019-08-07 11:46:30 -050084 .sw_if_index = sw_if_index,
85 };
Neale Ranns1ff3c152019-10-07 22:40:54 -070086 /* *INDENT-ON* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -050087
88 /* If prefix already set on interface, just increment ref count & return */
89 if_prefix = ip_get_interface_prefix (lm, &key);
90 if (if_prefix)
91 {
92 if_prefix->ref_count += 1;
93 return;
94 }
95
96 /* New prefix - allocate a pool entry, initialize it, add to the hash */
97 pool_get (lm->if_prefix_pool, if_prefix);
98 if_prefix->ref_count = 1;
99 clib_memcpy (&if_prefix->key, &key, sizeof (key));
100 mhash_set (&lm->prefix_to_if_prefix_index, &key,
101 if_prefix - lm->if_prefix_pool, 0 /* old value */ );
102
103 /* length < 128 - add glean */
104 if (address_length < 128)
105 {
106 /* set the glean route for the prefix */
107 fib_table_entry_update_one_path (fib_index, &key.prefix,
108 FIB_SOURCE_INTERFACE,
109 (FIB_ENTRY_FLAG_CONNECTED |
110 FIB_ENTRY_FLAG_ATTACHED),
111 DPO_PROTO_IP6,
112 /* No next-hop address */
113 NULL, sw_if_index,
114 /* invalid FIB index */
115 ~0, 1,
116 /* no out-label stack */
117 NULL, FIB_ROUTE_PATH_FLAG_NONE);
118 }
119}
120
121static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
123 ip6_main_t * im, u32 fib_index,
124 ip_interface_address_t * a)
125{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500126 ip_lookup_main_t *lm = &im->lookup_main;
127 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100128 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500129 .fp_len = a->address_length,
130 .fp_proto = FIB_PROTOCOL_IP6,
131 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500134 /* set special routes for the prefix if needed */
135 ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
136 address, a->address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100138 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500140 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100141 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 lm->classify_table_index_by_sw_if_index[sw_if_index];
143 if (classify_table_index != (u32) ~ 0)
144 {
145 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 dpo_set (&dpo,
148 DPO_CLASSIFY,
149 DPO_PROTO_IP6,
150 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100151
Dave Barachd7cb1b52016-12-09 09:52:16 -0500152 fib_table_entry_special_dpo_add (fib_index,
153 &pfx,
154 FIB_SOURCE_CLASSIFY,
155 FIB_ENTRY_FLAG_NONE, &dpo);
156 dpo_reset (&dpo);
157 }
158 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100159
Neale Rannsf12a83f2017-04-18 09:09:40 -0700160 fib_table_entry_update_one_path (fib_index, &pfx,
161 FIB_SOURCE_INTERFACE,
162 (FIB_ENTRY_FLAG_CONNECTED |
163 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700164 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700165 &pfx.fp_addr,
166 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500167 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168}
169
170static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500171ip6_del_interface_prefix_routes (ip6_main_t * im,
172 u32 sw_if_index,
173 u32 fib_index,
174 ip6_address_t * address, u32 address_length)
175{
176 ip_lookup_main_t *lm = &im->lookup_main;
177 ip_interface_prefix_t *if_prefix;
178
Neale Ranns1ff3c152019-10-07 22:40:54 -0700179 /* *INDENT-OFF* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500180 ip_interface_prefix_key_t key = {
181 .prefix = {
Neale Ranns1ff3c152019-10-07 22:40:54 -0700182 .fp_len = address_length,
183 .fp_proto = FIB_PROTOCOL_IP6,
184 .fp_addr.ip6 = {
185 .as_u64 = {
186 address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
187 address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
188 },
189 },
190 },
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500191 .sw_if_index = sw_if_index,
192 };
Neale Ranns1ff3c152019-10-07 22:40:54 -0700193 /* *INDENT-ON* */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500194
195 if_prefix = ip_get_interface_prefix (lm, &key);
196 if (!if_prefix)
197 {
198 clib_warning ("Prefix not found while deleting %U",
199 format_ip4_address_and_length, address, address_length);
200 return;
201 }
202
203 /* If not deleting last intf addr in prefix, decrement ref count & return */
204 if_prefix->ref_count -= 1;
205 if (if_prefix->ref_count > 0)
206 return;
207
Neale Ranns1ff3c152019-10-07 22:40:54 -0700208 /* length <= 128, delete glean route */
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500209 if (address_length <= 128)
210 {
211 /* remove glean route for prefix */
212 fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500213 }
214
215 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
216 pool_put (lm->if_prefix_pool, if_prefix);
217}
218
219static void
220ip6_del_interface_routes (u32 sw_if_index, ip6_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100221 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500222 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500224 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500225 .fp_len = 128,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500226 .fp_proto = FIB_PROTOCOL_IP6,
227 .fp_addr.ip6 = *address,
228 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500230 /* delete special routes for the prefix if needed */
231 ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
232 address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100233
Dave Barachd7cb1b52016-12-09 09:52:16 -0500234 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235}
236
Damjan Marion38173502019-02-13 19:30:09 +0100237#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100238void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500239ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100240{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500241 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100243 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100245 /*
246 * enable/disable only on the 1<->0 transition
247 */
248 if (is_enable)
249 {
250 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500251 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100252 }
253 else
254 {
Neale Ranns75152282017-01-09 01:00:45 -0800255 /* The ref count is 0 when an address is removed from an interface that has
256 * no address - this is not a ciritical error */
257 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
258 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100260 }
261
Neale Ranns8269d3d2018-01-30 09:02:20 -0800262 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Neale Ranns630198f2017-05-22 09:20:20 -0400263 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100264
Neale Ranns8269d3d2018-01-30 09:02:20 -0800265 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
266 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100267}
268
Neale Rannsdf089a82016-10-02 16:39:06 +0100269/* get first interface address */
270ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800271ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100272{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500273 ip_lookup_main_t *lm = &im->lookup_main;
274 ip_interface_address_t *ia = 0;
275 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100276
Dave Barachd7cb1b52016-12-09 09:52:16 -0500277 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100278 foreach_ip_interface_address (lm, ia, sw_if_index,
279 1 /* honor unnumbered */,
280 ({
281 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
282 result = a;
283 break;
284 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100286 return result;
287}
288
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100289clib_error_t *
290ip6_add_del_interface_address (vlib_main_t * vm,
291 u32 sw_if_index,
292 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500295 vnet_main_t *vnm = vnet_get_main ();
296 ip6_main_t *im = &ip6_main;
297 ip_lookup_main_t *lm = &im->lookup_main;
Neale Ranns59f71132020-04-08 12:19:38 +0000298 clib_error_t *error = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500300 ip6_address_fib_t ip6_af, *addr_fib = 0;
Neale Rannscbe25aa2019-09-30 10:53:31 +0000301 const ip6_address_t *ll_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
Pavel Kotucek57808982017-08-02 08:20:19 +0200303 /* local0 interface doesn't support IP addressing */
304 if (sw_if_index == 0)
305 {
306 return
307 clib_error_create ("local0 interface doesn't support IP addressing");
308 }
309
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200310 if (ip6_address_is_link_local_unicast (address))
311 {
312 if (address_length != 128)
313 {
314 vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
315 return
316 clib_error_create
317 ("prefix length of link-local address must be 128");
318 }
319 if (!is_del)
320 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000321 int rv;
322
Neale Rannsec40a7d2020-04-23 07:36:12 +0000323 rv = ip6_link_set_local_address (sw_if_index, address);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000324
325 if (rv)
326 {
327 vnm->api_errno = rv;
328 return clib_error_create ("address not assignable");
329 }
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200330 }
331 else
332 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000333 ll_addr = ip6_get_link_local_address (sw_if_index);
334 if (ip6_address_is_equal (ll_addr, address))
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200335 {
336 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
337 return clib_error_create ("address not deletable");
338 }
339 else
340 {
341 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
342 return clib_error_create ("address not found");
343 }
344 }
Neale Rannsec40a7d2020-04-23 07:36:12 +0000345
346 return (NULL);
Juraj Sloboda5bb1eca2018-10-22 09:57:13 +0200347 }
348
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000350 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
351
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 ip6_addr_fib_init (&ip6_af, address,
353 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
354 vec_add1 (addr_fib, ip6_af);
355
Neale Ranns744902e2017-08-14 10:35:44 -0700356 /* *INDENT-OFF* */
357 if (!is_del)
358 {
359 /* When adding an address check that it does not conflict
360 with an existing address on any interface in this table. */
361 ip_interface_address_t *ia;
362 vnet_sw_interface_t *sif;
363
364 pool_foreach(sif, vnm->interface_main.sw_interfaces,
365 ({
366 if (im->fib_index_by_sw_if_index[sw_if_index] ==
367 im->fib_index_by_sw_if_index[sif->sw_if_index])
368 {
369 foreach_ip_interface_address
370 (&im->lookup_main, ia, sif->sw_if_index,
371 0 /* honor unnumbered */ ,
372 ({
373 ip6_address_t * x =
374 ip_interface_address_get_address
375 (&im->lookup_main, ia);
Neale Ranns59f71132020-04-08 12:19:38 +0000376
Neale Ranns744902e2017-08-14 10:35:44 -0700377 if (ip6_destination_matches_route
378 (im, address, x, ia->address_length) ||
379 ip6_destination_matches_route (im,
380 x,
381 address,
382 address_length))
383 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500384 /* an intf may have >1 addr from the same prefix */
385 if ((sw_if_index == sif->sw_if_index) &&
386 (ia->address_length == address_length) &&
387 !ip6_address_is_equal (x, address))
388 continue;
389
Neale Ranns59f71132020-04-08 12:19:38 +0000390 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
391 /* if the address we're comparing against is stale
392 * then the CP has not added this one back yet, maybe
393 * it never will, so we have to assume it won't and
394 * ignore it. if it does add it back, then it will fail
395 * because this one is now present */
396 continue;
397
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500398 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700399 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
Neale Ranns59f71132020-04-08 12:19:38 +0000400 error = clib_error_create
Neale Ranns744902e2017-08-14 10:35:44 -0700401 ("failed to add %U which conflicts with %U for interface %U",
402 format_ip6_address_and_length, address,
403 address_length,
404 format_ip6_address_and_length, x,
405 ia->address_length,
406 format_vnet_sw_if_index_name, vnm,
407 sif->sw_if_index);
Neale Ranns59f71132020-04-08 12:19:38 +0000408 goto done;
Neale Ranns744902e2017-08-14 10:35:44 -0700409 }
410 }));
411 }
412 }));
413 }
414 /* *INDENT-ON* */
415
Neale Ranns59f71132020-04-08 12:19:38 +0000416 if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
Neale Ranns59f71132020-04-08 12:19:38 +0000418 if (is_del)
419 {
420 if (~0 == if_address_index)
421 {
422 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
423 error = clib_error_create ("%U not found for interface %U",
424 lm->format_address_and_length,
425 addr_fib, address_length,
426 format_vnet_sw_if_index_name, vnm,
427 sw_if_index);
428 goto done;
429 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Neale Ranns59f71132020-04-08 12:19:38 +0000431 ip_interface_address_del (lm, if_address_index, addr_fib);
432 }
433 else
434 {
435 if (~0 != if_address_index)
436 {
437 ip_interface_address_t *ia;
438
439 ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
440
441 if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
442 {
443 if (ia->sw_if_index == sw_if_index)
444 {
445 /* re-adding an address during the replace action.
446 * consdier this the update. clear the flag and
447 * we're done */
448 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
449 goto done;
450 }
451 else
452 {
453 /* The prefix is moving from one interface to another.
454 * delete the stale and add the new */
455 ip6_add_del_interface_address (vm,
456 ia->sw_if_index,
457 address, address_length, 1);
458 ia = NULL;
459 error = ip_interface_address_add (lm, sw_if_index,
460 addr_fib, address_length,
461 &if_address_index);
462 }
463 }
464 else
465 {
466 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
467 error = clib_error_create
468 ("Prefix %U already found on interface %U",
469 lm->format_address_and_length, addr_fib, address_length,
470 format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
471 }
472 }
473 else
474 error = ip_interface_address_add (lm, sw_if_index,
475 addr_fib, address_length,
476 &if_address_index);
477 }
478
479 if (error)
480 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Rannscbe25aa2019-09-30 10:53:31 +0000483 if (!is_del)
Neale Rannsec40a7d2020-04-23 07:36:12 +0000484 ip6_link_enable (sw_if_index, NULL);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000485
Neale Ranns1ff3c152019-10-07 22:40:54 -0700486 /* intf addr routes are added/deleted on admin up/down */
487 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
488 {
489 if (is_del)
490 ip6_del_interface_routes (sw_if_index,
491 im, ip6_af.fib_index, address,
492 address_length);
493 else
494 ip6_add_interface_routes (vnm, sw_if_index,
495 im, ip6_af.fib_index,
496 pool_elt_at_index (lm->if_address_pool,
497 if_address_index));
498 }
Neale Ranns59f71132020-04-08 12:19:38 +0000499
500 ip6_add_del_interface_address_callback_t *cb;
501 vec_foreach (cb, im->add_del_interface_address_callbacks)
502 cb->function (im, cb->function_opaque, sw_if_index,
503 address, address_length, if_address_index, is_del);
504
Neale Rannscbe25aa2019-09-30 10:53:31 +0000505 if (is_del)
506 ip6_link_disable (sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507
Dave Barachd7cb1b52016-12-09 09:52:16 -0500508done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700509 vec_free (addr_fib);
510 return error;
511}
512
Damjan Marion38173502019-02-13 19:30:09 +0100513#endif
514
515static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500516ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500518 ip6_main_t *im = &ip6_main;
519 ip_interface_address_t *ia;
520 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 u32 is_admin_up, fib_index;
522
523 /* Fill in lookup tables with default table (0). */
524 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
525
Dave Barachd7cb1b52016-12-09 09:52:16 -0500526 vec_validate_init_empty (im->
527 lookup_main.if_address_pool_index_by_sw_if_index,
528 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529
530 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
531
532 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
533
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400535 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 0 /* honor unnumbered */,
537 ({
538 a = ip_interface_address_get_address (&im->lookup_main, ia);
539 if (is_admin_up)
540 ip6_add_interface_routes (vnm, sw_if_index,
541 im, fib_index,
542 ia);
543 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500544 ip6_del_interface_routes (sw_if_index, im, fib_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 a, ia->address_length);
546 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548
549 return 0;
550}
551
552VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
553
Dave Barachd6534602016-06-14 18:38:02 -0400554/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500555/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100556VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
557{
558 .arc_name = "ip6-unicast",
559 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500560 .last_in_arc = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100561 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
562};
563
Dave Barachd7cb1b52016-12-09 09:52:16 -0500564VNET_FEATURE_INIT (ip6_flow_classify, static) =
565{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100566 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700567 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100568 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700569};
570
Dave Barachd7cb1b52016-12-09 09:52:16 -0500571VNET_FEATURE_INIT (ip6_inacl, static) =
572{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100573 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400574 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100575 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400576};
577
Dave Barachd7cb1b52016-12-09 09:52:16 -0500578VNET_FEATURE_INIT (ip6_policer_classify, static) =
579{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100580 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700581 .node_name = "ip6-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100582 .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700583};
584
Dave Barachd7cb1b52016-12-09 09:52:16 -0500585VNET_FEATURE_INIT (ip6_ipsec, static) =
586{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100587 .arc_name = "ip6-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100588 .node_name = "ipsec6-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100589 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400590};
591
Dave Barachd7cb1b52016-12-09 09:52:16 -0500592VNET_FEATURE_INIT (ip6_l2tp, static) =
593{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100594 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400595 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100596 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400597};
598
Dave Barachd7cb1b52016-12-09 09:52:16 -0500599VNET_FEATURE_INIT (ip6_vpath, static) =
600{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100601 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400602 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500603 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
604};
605
606VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
607{
608 .arc_name = "ip6-unicast",
609 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100610 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400611};
612
Neale Ranns8269d3d2018-01-30 09:02:20 -0800613VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500614{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100615 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800616 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400617 .runs_before = VNET_FEATURES ("ip6-lookup"),
618};
619
620VNET_FEATURE_INIT (ip6_lookup, static) =
621{
622 .arc_name = "ip6-unicast",
623 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100624 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100625};
626
Dave Barachd6534602016-06-14 18:38:02 -0400627/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100628VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
629{
630 .arc_name = "ip6-multicast",
631 .start_nodes = VNET_FEATURES ("ip6-input"),
Dave Baracha25def72018-11-26 11:04:45 -0500632 .last_in_arc = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100633 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
634};
635
636VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
637 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400638 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000639 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400640};
641
Neale Ranns8269d3d2018-01-30 09:02:20 -0800642VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100643 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800644 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400645 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
646};
647
648VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
649 .arc_name = "ip6-multicast",
650 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100651 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100652};
Dave Barach5331c722016-08-17 11:54:30 -0400653
654/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100655VNET_FEATURE_ARC_INIT (ip6_output, static) =
656{
657 .arc_name = "ip6-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800658 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -0500659 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100660 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400661};
662
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100663VNET_FEATURE_INIT (ip6_outacl, static) = {
664 .arc_name = "ip6-output",
665 .node_name = "ip6-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +0100666 .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100667};
668
Matus Fabian08a6f012016-11-15 06:08:51 -0800669VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
670 .arc_name = "ip6-output",
Pierre Pfister057b3562018-12-10 17:01:01 +0100671 .node_name = "ipsec6-output-feature",
Matus Fabian08a6f012016-11-15 06:08:51 -0800672 .runs_before = VNET_FEATURES ("interface-output"),
673};
674
Damjan Marion8b3191e2016-11-09 19:54:20 +0100675VNET_FEATURE_INIT (ip6_interface_output, static) = {
676 .arc_name = "ip6-output",
677 .node_name = "interface-output",
678 .runs_before = 0, /* not before any other features */
679};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500680/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400681
Damjan Marion38173502019-02-13 19:30:09 +0100682static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500683ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700685 ip6_main_t *im = &ip6_main;
686
687 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
688 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
689
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200690 if (!is_add)
691 {
692 /* Ensure that IPv6 is disabled */
693 ip6_main_t *im6 = &ip6_main;
694 ip_lookup_main_t *lm6 = &im6->lookup_main;
695 ip_interface_address_t *ia = 0;
696 ip6_address_t *address;
697 vlib_main_t *vm = vlib_get_main ();
698
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700699 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200700 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700701 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200702 ({
703 address = ip_interface_address_get_address (lm6, ia);
704 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
705 }));
706 /* *INDENT-ON* */
707 ip6_mfib_interface_enable_disable (sw_if_index, 0);
708 }
709
Neale Ranns8269d3d2018-01-30 09:02:20 -0800710 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100711 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700712
Neale Ranns8269d3d2018-01-30 09:02:20 -0800713 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
714 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716 return /* no error */ 0;
717}
718
719VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
720
Damjan Marion38173502019-02-13 19:30:09 +0100721VLIB_NODE_FN (ip6_lookup_node) (vlib_main_t * vm,
722 vlib_node_runtime_t * node,
723 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200724{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100725 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200726}
727
Dave Barachd7cb1b52016-12-09 09:52:16 -0500728static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100729
Dave Barachd7cb1b52016-12-09 09:52:16 -0500730/* *INDENT-OFF* */
731VLIB_REGISTER_NODE (ip6_lookup_node) =
732{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 .name = "ip6-lookup",
734 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100735 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200736 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200737 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
Damjan Marion38173502019-02-13 19:30:09 +0100741VLIB_NODE_FN (ip6_load_balance_node) (vlib_main_t * vm,
742 vlib_node_runtime_t * node,
743 vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200744{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500745 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400746 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200747 u32 thread_index = vm->thread_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500748 ip6_main_t *im = &ip6_main;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400749 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
750 u16 nexts[VLIB_FRAME_SIZE], *next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100751
752 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400753 n_left = frame->n_vectors;
754 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100755
Neale Ranns3ce72b22019-05-27 08:21:32 -0400756 vlib_get_buffers (vm, from, bufs, n_left);
757
758 while (n_left >= 4)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400760 const load_balance_t *lb0, *lb1;
761 const ip6_header_t *ip0, *ip1;
762 u32 lbi0, hc0, lbi1, hc1;
763 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764
Neale Ranns3ce72b22019-05-27 08:21:32 -0400765 /* Prefetch next iteration. */
766 {
767 vlib_prefetch_buffer_header (b[2], STORE);
768 vlib_prefetch_buffer_header (b[3], STORE);
Dave Barach75fc8542016-10-11 16:16:02 -0400769
Neale Ranns3ce72b22019-05-27 08:21:32 -0400770 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
771 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
772 }
773
774 ip0 = vlib_buffer_get_current (b[0]);
775 ip1 = vlib_buffer_get_current (b[1]);
776 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
777 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
778
779 lb0 = load_balance_get (lbi0);
780 lb1 = load_balance_get (lbi1);
781
782 /*
783 * this node is for via FIBs we can re-use the hash value from the
784 * to node if present.
785 * We don't want to use the same hash value at each level in the recursion
786 * graph as that would lead to polarisation
787 */
788 hc0 = hc1 = 0;
789
790 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500791 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400792 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500793 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400794 hc0 = vnet_buffer (b[0])->ip.flow_hash =
795 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700796 }
797 else
798 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400799 hc0 = vnet_buffer (b[0])->ip.flow_hash =
800 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400802 dpo0 = load_balance_get_fwd_bucket
803 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
804 }
805 else
806 {
807 dpo0 = load_balance_get_bucket_i (lb0, 0);
808 }
809 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
810 {
811 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400813 hc1 = vnet_buffer (b[1])->ip.flow_hash =
814 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500815 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700816 else
817 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400818 hc1 = vnet_buffer (b[1])->ip.flow_hash =
819 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700820 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400821 dpo1 = load_balance_get_fwd_bucket
822 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
823 }
824 else
825 {
826 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500827 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000828
Neale Ranns3ce72b22019-05-27 08:21:32 -0400829 next[0] = dpo0->dpoi_next_node;
830 next[1] = dpo1->dpoi_next_node;
831
832 /* Only process the HBH Option Header if explicitly configured to do so */
833 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500834 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400835 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
836 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
837 }
838 /* Only process the HBH Option Header if explicitly configured to do so */
839 if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
840 {
841 next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
842 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[1];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500843 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100844
Neale Ranns3ce72b22019-05-27 08:21:32 -0400845 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
846 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
847
848 vlib_increment_combined_counter
849 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
850 vlib_increment_combined_counter
851 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
852
853 b += 2;
854 next += 2;
855 n_left -= 2;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100856 }
857
Neale Ranns3ce72b22019-05-27 08:21:32 -0400858 while (n_left > 0)
859 {
860 const load_balance_t *lb0;
861 const ip6_header_t *ip0;
862 const dpo_id_t *dpo0;
863 u32 lbi0, hc0;
864
865 ip0 = vlib_buffer_get_current (b[0]);
866 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
867
868 lb0 = load_balance_get (lbi0);
869
870 hc0 = 0;
871 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
872 {
873 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
874 {
875 hc0 = vnet_buffer (b[0])->ip.flow_hash =
876 vnet_buffer (b[0])->ip.flow_hash >> 1;
877 }
878 else
879 {
880 hc0 = vnet_buffer (b[0])->ip.flow_hash =
881 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
882 }
883 dpo0 = load_balance_get_fwd_bucket
884 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
885 }
886 else
887 {
888 dpo0 = load_balance_get_bucket_i (lb0, 0);
889 }
890
891 next[0] = dpo0->dpoi_next_node;
892 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
893
894 /* Only process the HBH Option Header if explicitly configured to do so */
895 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
896 {
897 next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
898 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next[0];
899 }
900
901 vlib_increment_combined_counter
902 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
903
904 b += 1;
905 next += 1;
906 n_left -= 1;
907 }
908
909 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
910
Neale Rannsa71844f2018-11-08 07:31:36 -0800911 if (node->flags & VLIB_NODE_FLAG_TRACE)
912 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
913
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100914 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200915}
916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917/* *INDENT-OFF* */
918VLIB_REGISTER_NODE (ip6_load_balance_node) =
919{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100920 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200921 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200922 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100923 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200924};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200926
Dave Barachd7cb1b52016-12-09 09:52:16 -0500927typedef struct
928{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929 /* Adjacency taken. */
930 u32 adj_index;
931 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500932 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933
934 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935 u8 packet_data[128 - 1 * sizeof (u32)];
936}
937ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938
Damjan Marion38173502019-02-13 19:30:09 +0100939#ifndef CLIB_MARCH_VARIANT
John Lo2b81eb82017-01-30 13:12:10 -0500940u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500941format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100943 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
944 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200946 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100947
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948 s = format (s, "%U%U",
949 format_white_space, indent,
950 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100951 return s;
952}
Damjan Marion38173502019-02-13 19:30:09 +0100953#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100954
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955static u8 *
956format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100957{
958 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
959 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500960 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200961 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700962
John Loac8146c2016-09-27 17:44:02 -0400963 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500964 t->fib_index, t->adj_index, t->flow_hash);
965 s = format (s, "\n%U%U",
966 format_white_space, indent,
967 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100968 return s;
969}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100970
Ed Warnickecb9cada2015-12-08 15:45:58 -0700971
Dave Barachd7cb1b52016-12-09 09:52:16 -0500972static u8 *
973format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100974{
975 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
976 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500977 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200978 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100980 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981 t->fib_index, t->adj_index, format_ip_adjacency,
982 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100983 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500984 format_white_space, indent,
985 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +0000986 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700987 return s;
988}
989
990/* Common trace function for all ip6-forward next nodes. */
Damjan Marion38173502019-02-13 19:30:09 +0100991#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992void
993ip6_forward_next_trace (vlib_main_t * vm,
994 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700996{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500997 u32 *from, n_left;
998 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700999
1000 n_left = frame->n_vectors;
1001 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001002
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003 while (n_left >= 4)
1004 {
1005 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001006 vlib_buffer_t *b0, *b1;
1007 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008
1009 /* Prefetch next iteration. */
1010 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1011 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1012
1013 bi0 = from[0];
1014 bi1 = from[1];
1015
1016 b0 = vlib_get_buffer (vm, bi0);
1017 b1 = vlib_get_buffer (vm, bi1);
1018
1019 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1020 {
1021 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1022 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001023 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1024 t0->fib_index =
1025 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1026 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1027 vec_elt (im->fib_index_by_sw_if_index,
1028 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001029
Dave Barach178cf492018-11-13 16:34:13 -05001030 clib_memcpy_fast (t0->packet_data,
1031 vlib_buffer_get_current (b0),
1032 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 }
1034 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1035 {
1036 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1037 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001038 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1039 t1->fib_index =
1040 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1041 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1042 vec_elt (im->fib_index_by_sw_if_index,
1043 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001044
Dave Barach178cf492018-11-13 16:34:13 -05001045 clib_memcpy_fast (t1->packet_data,
1046 vlib_buffer_get_current (b1),
1047 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 }
1049 from += 2;
1050 n_left -= 2;
1051 }
1052
1053 while (n_left >= 1)
1054 {
1055 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001056 vlib_buffer_t *b0;
1057 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058
1059 bi0 = from[0];
1060
1061 b0 = vlib_get_buffer (vm, bi0);
1062
1063 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1064 {
1065 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1066 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001067 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1068 t0->fib_index =
1069 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1070 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1071 vec_elt (im->fib_index_by_sw_if_index,
1072 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001073
Dave Barach178cf492018-11-13 16:34:13 -05001074 clib_memcpy_fast (t0->packet_data,
1075 vlib_buffer_get_current (b0),
1076 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 }
1078 from += 1;
1079 n_left -= 1;
1080 }
1081}
1082
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001084u16
1085ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1086 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001087{
Matthew Smith97677a22020-02-05 11:46:40 -06001088 ip_csum_t sum0 = 0;
1089 u16 payload_length, payload_length_host_byte_order;
Srikanth A02833ff2019-10-02 17:48:58 -07001090 u32 i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001091 u32 headers_size = sizeof (ip0[0]);
Dave Barachc4abafd2019-09-04 12:09:32 -04001092 u8 *data_this_buffer;
Matthew Smith97677a22020-02-05 11:46:40 -06001093 u8 next_hdr = ip0->protocol;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001094
Dave Barachd7cb1b52016-12-09 09:52:16 -05001095 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 *bogus_lengthp = 0;
1097
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
Dave Barachc4abafd2019-09-04 12:09:32 -04001099 data_this_buffer = (u8 *) (ip0 + 1);
Matthew Smith97677a22020-02-05 11:46:40 -06001100 payload_length = ip0->payload_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301102 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1103 * or UDP-Ping packets */
Matthew Smith97677a22020-02-05 11:46:40 -06001104 if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001106 u32 skip_bytes;
1107 ip6_hop_by_hop_ext_t *ext_hdr =
1108 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109
1110 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301111 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1112 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
Dave Barachd7cb1b52016-12-09 09:52:16 -05001114 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1115 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001116
Dave Barachd7cb1b52016-12-09 09:52:16 -05001117 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 headers_size += skip_bytes;
Matthew Smith97677a22020-02-05 11:46:40 -06001119
1120 /* pseudo-header adjustments:
1121 * exclude ext header bytes from payload length
1122 * use payload IP proto rather than ext header IP proto
1123 */
1124 payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1125 next_hdr = ext_hdr->next_hdr;
1126 }
1127
1128 /* Initialize checksum with ip pseudo-header. */
1129 sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1130
1131 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1132 {
1133 sum0 = ip_csum_with_carry
1134 (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1135 sum0 = ip_csum_with_carry
1136 (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001137 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138
John Lo3bc6bc22019-08-03 14:36:39 -04001139 if (p0)
Srikanth A02833ff2019-10-02 17:48:58 -07001140 return ip_calculate_l4_checksum (vm, p0, sum0,
1141 payload_length_host_byte_order,
1142 (u8 *) ip0, headers_size, NULL);
1143 else
1144 return ip_calculate_l4_checksum (vm, 0, sum0,
1145 payload_length_host_byte_order, NULL, 0,
1146 data_this_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147}
1148
Dave Barachd7cb1b52016-12-09 09:52:16 -05001149u32
1150ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001152 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1153 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154 u16 sum16;
1155 int bogus_length;
1156
1157 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1158 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1159 || ip0->protocol == IP_PROTOCOL_ICMP6
1160 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001161 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162
1163 udp0 = (void *) (ip0 + 1);
1164 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1165 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001166 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1167 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168 return p0->flags;
1169 }
1170
1171 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1172
Damjan Marion213b5aa2017-07-13 21:19:27 +02001173 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1174 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175
1176 return p0->flags;
1177}
Damjan Marion38173502019-02-13 19:30:09 +01001178#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301180/**
1181 * @brief returns number of links on which src is reachable.
1182 */
1183always_inline int
1184ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1185{
1186 const load_balance_t *lb0;
1187 index_t lbi;
Florin Corasf3a3bad2018-03-28 02:18:29 -07001188 u32 fib_index;
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301189
Florin Corasf3a3bad2018-03-28 02:18:29 -07001190 fib_index = vec_elt (im->fib_index_by_sw_if_index,
1191 vnet_buffer (b)->sw_if_index[VLIB_RX]);
1192 fib_index =
1193 (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1194 fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301195
Simon Zhange7eba482019-08-25 15:30:45 +08001196 lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301197 lb0 = load_balance_get (lbi);
1198
1199 return (fib_urpf_check_size (lb0->lb_urpf));
1200}
1201
rootc9d1c5b2017-08-15 12:58:31 -04001202always_inline u8
1203ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1204 u32 * udp_offset0)
1205{
1206 u32 proto0;
1207 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1208 if (proto0 != IP_PROTOCOL_UDP)
1209 {
1210 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1211 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1212 }
1213 return proto0;
1214}
1215
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001216/* *INDENT-OFF* */
1217VNET_FEATURE_ARC_INIT (ip6_local) =
1218{
1219 .arc_name = "ip6-local",
1220 .start_nodes = VNET_FEATURES ("ip6-local"),
1221};
1222/* *INDENT-ON* */
1223
johny17478e42019-10-11 18:28:51 +02001224static_always_inline u8
1225ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
1226{
1227
1228 u16 payload_length_host_byte_order;
1229 u32 n_this_buffer, n_bytes_left;
1230 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1231 u32 headers_size = sizeof (ip0[0]);
1232 u8 *data_this_buffer;
1233
1234
1235 data_this_buffer = (u8 *) (ip0 + 1);
1236
1237 ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1238
1239 /* validate really icmp6 next */
1240
1241 if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1242 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1243 return 0;
1244
1245
1246 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1247 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1248
johnya633a432019-12-06 13:58:35 +01001249
1250 u32 n_ip_bytes_this_buffer =
1251 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1252 if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
johny17478e42019-10-11 18:28:51 +02001253 {
johnya633a432019-12-06 13:58:35 +01001254 n_this_buffer = p0->current_length > headers_size ?
1255 n_ip_bytes_this_buffer - headers_size : 0;
johny17478e42019-10-11 18:28:51 +02001256 }
1257
1258 n_bytes_left -= n_this_buffer;
1259 n_bytes_left -= p0->total_length_not_including_first_buffer;
1260
1261 if (n_bytes_left == 0)
1262 return 0;
1263 else
1264 return 1;
1265}
1266
1267
Benoît Ganne26a10192019-02-14 15:32:45 +01001268always_inline uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001269ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1270 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 ip6_main_t *im = &ip6_main;
1273 ip_lookup_main_t *lm = &im->lookup_main;
Benoît Ganne26a10192019-02-14 15:32:45 +01001274 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001275 vlib_node_runtime_t *error_node =
1276 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001277 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001278 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1279 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280
1281 from = vlib_frame_vector_args (frame);
1282 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001283
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284 if (node->flags & VLIB_NODE_FLAG_TRACE)
1285 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1286
Benoît Ganne26a10192019-02-14 15:32:45 +01001287 vlib_get_buffers (vm, from, bufs, n_left_from);
1288 b = bufs;
1289 next = nexts;
1290
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001291 while (n_left_from > 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001292 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001293 /* Prefetch next iteration. */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001294 if (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001296 vlib_prefetch_buffer_header (b[4], STORE);
1297 vlib_prefetch_buffer_header (b[5], STORE);
1298 vlib_prefetch_buffer_data (b[2], LOAD);
1299 vlib_prefetch_buffer_data (b[3], LOAD);
Benoît Ganne26a10192019-02-14 15:32:45 +01001300 }
Dave Barach75fc8542016-10-11 16:16:02 -04001301
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001302 u8 error[2];
1303 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1304 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
Dave Barach75fc8542016-10-11 16:16:02 -04001305
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001306 ip6_header_t *ip[2];
1307 ip[0] = vlib_buffer_get_current (b[0]);
1308 ip[1] = vlib_buffer_get_current (b[1]);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001309
Benoît Ganne26a10192019-02-14 15:32:45 +01001310 if (head_of_feature_arc)
1311 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001312 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1313 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001315 u8 type[2];
1316 type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1317 type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001319 u32 flags[2];
1320 flags[0] = b[0]->flags;
1321 flags[1] = b[1]->flags;
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001322
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001323 u32 good_l4_csum[2];
1324 good_l4_csum[0] =
1325 flags[0] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1326 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1327 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1328 good_l4_csum[1] =
1329 flags[1] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
Benoît Ganne26a10192019-02-14 15:32:45 +01001330 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1331 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
Filip Tehlarb601f222017-01-02 10:22:56 +01001332
Damjan Marion34e823f2019-02-19 08:55:18 +01001333 u32 udp_offset[2] = { };
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001334 u8 is_tcp_udp[2];
1335 is_tcp_udp[0] =
1336 ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1337 is_tcp_udp[1] =
1338 ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1339 i16 len_diff[2] = { 0 };
1340 if (PREDICT_TRUE (is_tcp_udp[0]))
Shwethab78292e2016-09-13 11:51:00 +01001341 {
Benoît Ganne26a10192019-02-14 15:32:45 +01001342 udp_header_t *udp =
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001343 (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1344 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
Benoît Ganne26a10192019-02-14 15:32:45 +01001345 && udp->checksum == 0;
1346 /* optimistically verify UDP length. */
1347 u16 ip_len, udp_len;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001348 ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
Benoît Ganne26a10192019-02-14 15:32:45 +01001349 udp_len = clib_net_to_host_u16 (udp->length);
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001350 len_diff[0] = ip_len - udp_len;
Shwethab78292e2016-09-13 11:51:00 +01001351 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001352 if (PREDICT_TRUE (is_tcp_udp[1]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001354 udp_header_t *udp =
1355 (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1356 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1357 && udp->checksum == 0;
1358 /* optimistically verify UDP length. */
1359 u16 ip_len, udp_len;
1360 ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1361 udp_len = clib_net_to_host_u16 (udp->length);
1362 len_diff[1] = ip_len - udp_len;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363 }
1364
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001365 good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1366 good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1367
1368 len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1369 len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1370
1371 u8 need_csum[2];
1372 need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1373 && !good_l4_csum[0]
1374 && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1375 need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1376 && !good_l4_csum[1]
1377 && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1378 if (PREDICT_FALSE (need_csum[0]))
1379 {
1380 flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1381 good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001382 error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1383 }
1384 else
1385 {
1386 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1387 error[0] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001388 }
1389 if (PREDICT_FALSE (need_csum[1]))
1390 {
1391 flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1392 good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001393 error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1394 }
1395 else
1396 {
1397 if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1398 error[1] = IP6_ERROR_BAD_LENGTH;
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001399 }
1400
johny17478e42019-10-11 18:28:51 +02001401
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001402 error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
johny17478e42019-10-11 18:28:51 +02001403
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001404 error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405
Benoît Ganne26a10192019-02-14 15:32:45 +01001406 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1407 IP6_ERROR_UDP_CHECKSUM,
1408 "Wrong IP6 errors constants");
1409 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1410 IP6_ERROR_ICMP_CHECKSUM,
1411 "Wrong IP6 errors constants");
1412
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001413 error[0] =
1414 !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1415 error[1] =
1416 !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417
1418 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001419 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001420 u8 unroutable[2];
1421 unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1422 && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1423 && !ip6_address_is_link_local_unicast (&ip[0]->src_address);
1424 unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1425 && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1426 && !ip6_address_is_link_local_unicast (&ip[1]->src_address);
1427 if (PREDICT_FALSE (unroutable[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001428 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001429 error[0] =
1430 !ip6_urpf_loose_check (im, b[0],
1431 ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1432 : error[0];
1433 }
1434 if (PREDICT_FALSE (unroutable[1]))
1435 {
1436 error[1] =
1437 !ip6_urpf_loose_check (im, b[1],
1438 ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1439 : error[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001440 }
1441
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001442 vnet_buffer (b[0])->ip.fib_index =
1443 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1444 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1445 vnet_buffer (b[0])->ip.fib_index;
1446 vnet_buffer (b[1])->ip.fib_index =
1447 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1448 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1449 vnet_buffer (b[1])->ip.fib_index;
Benoît Ganne26a10192019-02-14 15:32:45 +01001450 } /* head_of_feature_arc */
Florin Corascea194d2017-10-02 00:18:51 -07001451
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001452 next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1453 next[0] =
1454 error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1455 next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1456 next[1] =
1457 error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
Florin Corascea194d2017-10-02 00:18:51 -07001458
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001459 b[0]->error = error_node->errors[0];
1460 b[1]->error = error_node->errors[1];
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001461
Benoît Ganne26a10192019-02-14 15:32:45 +01001462 if (head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001463 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001464 u8 ip6_unknown[2];
1465 ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1466 ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1467 if (PREDICT_TRUE (ip6_unknown[0]))
Shwethab78292e2016-09-13 11:51:00 +01001468 {
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001469 u32 next32 = next[0];
Benoît Ganne26a10192019-02-14 15:32:45 +01001470 vnet_feature_arc_start (arc_index,
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001471 vnet_buffer (b[0])->sw_if_index
1472 [VLIB_RX], &next32, b[0]);
1473 next[0] = next32;
1474 }
1475 if (PREDICT_TRUE (ip6_unknown[1]))
1476 {
1477 u32 next32 = next[1];
1478 vnet_feature_arc_start (arc_index,
1479 vnet_buffer (b[1])->sw_if_index
1480 [VLIB_RX], &next32, b[1]);
1481 next[1] = next32;
Shwethab78292e2016-09-13 11:51:00 +01001482 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483 }
Dave Barach75fc8542016-10-11 16:16:02 -04001484
Benoît Ganne26a10192019-02-14 15:32:45 +01001485 /* next */
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001486 b += 2;
1487 next += 2;
1488 n_left_from -= 2;
Benoît Ganne26a10192019-02-14 15:32:45 +01001489 }
Benoît Ganne7dcb80a2019-02-14 15:32:45 +01001490
Benoît Ganne26a10192019-02-14 15:32:45 +01001491 while (n_left_from)
1492 {
1493 u8 error;
1494 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1495
1496 ip6_header_t *ip;
1497 ip = vlib_buffer_get_current (b[0]);
1498
1499 if (head_of_feature_arc)
1500 {
1501 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1502 u8 type = lm->builtin_protocol_by_ip_protocol[ip->protocol];
1503
1504 u32 flags = b[0]->flags;
1505 u32 good_l4_csum =
1506 flags & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1507 VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1508 VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1509
1510 u32 udp_offset;
1511 i16 len_diff = 0;
1512 u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1513 if (PREDICT_TRUE (is_tcp_udp))
1514 {
1515 udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1516 /* Don't verify UDP checksum for packets with explicit zero checksum. */
1517 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1518 && udp->checksum == 0;
1519 /* optimistically verify UDP length. */
1520 u16 ip_len, udp_len;
1521 ip_len = clib_net_to_host_u16 (ip->payload_length);
1522 udp_len = clib_net_to_host_u16 (udp->length);
1523 len_diff = ip_len - udp_len;
1524 }
1525
1526 good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1527 len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1528
1529 u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN && !good_l4_csum
1530 && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1531 if (PREDICT_FALSE (need_csum))
1532 {
1533 flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1534 good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
johny17478e42019-10-11 18:28:51 +02001535 error = IP6_ERROR_UNKNOWN_PROTOCOL;
1536 }
1537 else
1538 {
1539 if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1540 error = IP6_ERROR_BAD_LENGTH;
Benoît Ganne26a10192019-02-14 15:32:45 +01001541 }
1542
johny17478e42019-10-11 18:28:51 +02001543
1544
Benoît Ganne26a10192019-02-14 15:32:45 +01001545 error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
1546
1547 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1548 IP6_ERROR_UDP_CHECKSUM,
1549 "Wrong IP6 errors constants");
1550 STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1551 IP6_ERROR_ICMP_CHECKSUM,
1552 "Wrong IP6 errors constants");
1553
1554 error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1555
1556 /* Drop packets from unroutable hosts. */
1557 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1558 u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1559 && type != IP_BUILTIN_PROTOCOL_ICMP
1560 && !ip6_address_is_link_local_unicast (&ip->src_address);
1561 if (PREDICT_FALSE (unroutable))
1562 {
1563 error =
1564 !ip6_urpf_loose_check (im, b[0],
1565 ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1566 error;
1567 }
1568
1569 vnet_buffer (b[0])->ip.fib_index =
1570 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1571 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1572 vnet_buffer (b[0])->ip.fib_index;
1573 } /* head_of_feature_arc */
1574
1575 next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1576 next[0] =
1577 error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1578
1579 b[0]->error = error_node->errors[0];
1580
1581 if (head_of_feature_arc)
1582 {
1583 if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1584 {
1585 u32 next32 = next[0];
1586 vnet_feature_arc_start (arc_index,
1587 vnet_buffer (b[0])->sw_if_index
1588 [VLIB_RX], &next32, b[0]);
1589 next[0] = next32;
1590 }
1591 }
1592
1593 /* next */
1594 b += 1;
1595 next += 1;
1596 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 }
1598
Benoît Ganne26a10192019-02-14 15:32:45 +01001599 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 return frame->n_vectors;
1601}
1602
Damjan Marion38173502019-02-13 19:30:09 +01001603VLIB_NODE_FN (ip6_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1604 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001605{
1606 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1607}
1608
Dave Barachd7cb1b52016-12-09 09:52:16 -05001609/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001610VLIB_REGISTER_NODE (ip6_local_node) =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001611{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001612 .name = "ip6-local",
1613 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001614 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001616 .next_nodes =
1617 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001618 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1619 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1621 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001622 [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001623 },
1624};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001625/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001626
Damjan Marion38173502019-02-13 19:30:09 +01001627VLIB_NODE_FN (ip6_local_end_of_arc_node) (vlib_main_t * vm,
1628 vlib_node_runtime_t * node,
1629 vlib_frame_t * frame)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001630{
1631 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1632}
1633
1634/* *INDENT-OFF* */
Damjan Marion38173502019-02-13 19:30:09 +01001635VLIB_REGISTER_NODE (ip6_local_end_of_arc_node) = {
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001636 .name = "ip6-local-end-of-arc",
1637 .vector_size = sizeof (u32),
1638
1639 .format_trace = format_ip6_forward_next_trace,
1640 .sibling_of = "ip6-local",
1641};
1642
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001643VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1644 .arc_name = "ip6-local",
1645 .node_name = "ip6-local-end-of-arc",
1646 .runs_before = 0, /* not before any other features */
1647};
1648/* *INDENT-ON* */
1649
Damjan Marion38173502019-02-13 19:30:09 +01001650#ifdef CLIB_MARCH_VARIANT
1651extern vlib_node_registration_t ip6_local_node;
Damjan Marion38173502019-02-13 19:30:09 +01001652#else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001653void
1654ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001655{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001656 vlib_main_t *vm = vlib_get_main ();
1657 ip6_main_t *im = &ip6_main;
1658 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
1660 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001661 lm->local_next_by_ip_protocol[protocol] =
1662 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663}
1664
Neale Rannsb538dd82019-05-21 06:54:54 -07001665void
1666ip6_unregister_protocol (u32 protocol)
1667{
1668 ip6_main_t *im = &ip6_main;
1669 ip_lookup_main_t *lm = &im->lookup_main;
1670
1671 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1672 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1673}
Damjan Marion38173502019-02-13 19:30:09 +01001674#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001675
Dave Barachd7cb1b52016-12-09 09:52:16 -05001676typedef enum
1677{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001679 IP6_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001680 IP6_REWRITE_NEXT_FRAGMENT,
1681 IP6_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001682} ip6_rewrite_next_t;
1683
Neale Ranns889fe942017-06-01 05:43:19 -04001684/**
1685 * This bits of an IPv6 address to mask to construct a multicast
1686 * MAC address
1687 */
1688#define IP6_MCAST_ADDR_MASK 0xffffffff
1689
Ole Troanda6e11b2018-05-23 11:21:42 +02001690always_inline void
1691ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
Ole Troan313f7e22018-04-10 16:02:51 +02001692 u16 adj_packet_bytes, bool is_locally_generated,
Ole Troaneb284a12019-10-09 13:33:19 +02001693 u32 * next, u8 is_midchain, u32 * error)
Ole Troanda6e11b2018-05-23 11:21:42 +02001694{
1695 if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1696 {
Ole Troan313f7e22018-04-10 16:02:51 +02001697 if (is_locally_generated)
1698 {
1699 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02001700 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001701 (is_midchain ?
1702 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1703 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02001704 *next = IP6_REWRITE_NEXT_FRAGMENT;
Ole Troan282093f2018-09-19 12:38:51 +02001705 *error = IP6_ERROR_MTU_EXCEEDED;
Ole Troan313f7e22018-04-10 16:02:51 +02001706 }
1707 else
1708 {
1709 *error = IP6_ERROR_MTU_EXCEEDED;
1710 icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1711 adj_packet_bytes);
1712 *next = IP6_REWRITE_NEXT_ICMP_ERROR;
1713 }
Ole Troanda6e11b2018-05-23 11:21:42 +02001714 }
1715}
1716
Ed Warnickecb9cada2015-12-08 15:45:58 -07001717always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001718ip6_rewrite_inline_with_gso (vlib_main_t * vm,
1719 vlib_node_runtime_t * node,
1720 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001721 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001722{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001723 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1724 u32 *from = vlib_frame_vector_args (frame);
1725 u32 n_left_from, n_left_to_next, *to_next, next_index;
1726 vlib_node_runtime_t *error_node =
1727 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728
1729 n_left_from = frame->n_vectors;
1730 next_index = node->cached_next_index;
Damjan Marion067cd622018-07-11 12:47:43 +02001731 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001732
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733 while (n_left_from > 0)
1734 {
1735 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1736
1737 while (n_left_from >= 4 && n_left_to_next >= 2)
1738 {
Neale Ranns960eeea2019-12-02 23:28:50 +00001739 const ip_adjacency_t *adj0, *adj1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001740 vlib_buffer_t *p0, *p1;
1741 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001742 u32 pi0, rw_len0, next0, error0, adj_index0;
1743 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001744 u32 tx_sw_if_index0, tx_sw_if_index1;
Ole Troan313f7e22018-04-10 16:02:51 +02001745 bool is_locally_originated0, is_locally_originated1;
Dave Barach75fc8542016-10-11 16:16:02 -04001746
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747 /* Prefetch next iteration. */
1748 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750
1751 p2 = vlib_get_buffer (vm, from[2]);
1752 p3 = vlib_get_buffer (vm, from[3]);
1753
1754 vlib_prefetch_buffer_header (p2, LOAD);
1755 vlib_prefetch_buffer_header (p3, LOAD);
1756
1757 CLIB_PREFETCH (p2->pre_data, 32, STORE);
1758 CLIB_PREFETCH (p3->pre_data, 32, STORE);
1759
1760 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1761 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1762 }
1763
1764 pi0 = to_next[0] = from[0];
1765 pi1 = to_next[1] = from[1];
1766
1767 from += 2;
1768 n_left_from -= 2;
1769 to_next += 2;
1770 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001771
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 p0 = vlib_get_buffer (vm, pi0);
1773 p1 = vlib_get_buffer (vm, pi1);
1774
Neale Rannsf06aea52016-11-29 06:51:37 -08001775 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1776 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778 ip0 = vlib_buffer_get_current (p0);
1779 ip1 = vlib_buffer_get_current (p1);
1780
1781 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001782 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001783
Ole Troan313f7e22018-04-10 16:02:51 +02001784 is_locally_originated0 =
1785 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1786 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001788 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001789
1790 /* Input node should have reject packets with hop limit 0. */
1791 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792
1793 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001794
1795 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796
Dave Barachd7cb1b52016-12-09 09:52:16 -05001797 /*
1798 * If the hop count drops below 1 when forwarding, generate
1799 * an ICMP response.
1800 */
1801 if (PREDICT_FALSE (hop_limit0 <= 0))
1802 {
1803 error0 = IP6_ERROR_TIME_EXPIRED;
1804 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1805 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1806 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1807 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1808 0);
1809 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001810 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001811
Ole Troan313f7e22018-04-10 16:02:51 +02001812 is_locally_originated1 =
1813 p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1814 if (PREDICT_TRUE (!is_locally_originated1))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001815 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001816 i32 hop_limit1 = ip1->hop_limit;
1817
1818 /* Input node should have reject packets with hop limit 0. */
1819 ASSERT (ip1->hop_limit > 0);
1820
1821 hop_limit1 -= 1;
1822
1823 ip1->hop_limit = hop_limit1;
1824
Dave Barachd7cb1b52016-12-09 09:52:16 -05001825 /*
1826 * If the hop count drops below 1 when forwarding, generate
1827 * an ICMP response.
1828 */
1829 if (PREDICT_FALSE (hop_limit1 <= 0))
1830 {
1831 error1 = IP6_ERROR_TIME_EXPIRED;
1832 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1833 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1834 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1835 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1836 0);
1837 }
1838 }
Neale Ranns88cecfa2020-04-08 08:28:06 -04001839
Neale Ranns107e7d42017-04-11 09:55:19 -07001840 adj0 = adj_get (adj_index0);
1841 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 rw_len0 = adj0[0].rewrite_header.data_bytes;
1844 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001845 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1846 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847
Neale Ranns9c6a6132017-02-21 05:33:14 -08001848 if (do_counters)
1849 {
1850 vlib_increment_combined_counter
1851 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001852 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001853 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1854 vlib_increment_combined_counter
1855 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001856 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001857 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1858 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859
1860 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001861 u16 ip0_len =
1862 clib_net_to_host_u16 (ip0->payload_length) +
1863 sizeof (ip6_header_t);
1864 u16 ip1_len =
1865 clib_net_to_host_u16 (ip1->payload_length) +
1866 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001867 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001868 ip0_len = gso_mtu_sz (p0);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01001869 if (p1->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001870 ip1_len = gso_mtu_sz (p1);
1871
1872
1873
1874 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001875 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001876 is_locally_originated0, &next0, is_midchain,
1877 &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001878 ip6_mtu_check (p1, ip1_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02001879 adj1[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02001880 is_locally_originated1, &next1, is_midchain,
1881 &error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883 /* Don't adjust the buffer for hop count issue; icmp-error node
Jim Thompsonf324dec2019-04-08 03:22:21 -05001884 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001885 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1886 {
1887 p0->current_data -= rw_len0;
1888 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001889
Dave Barachd7cb1b52016-12-09 09:52:16 -05001890 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1891 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1892 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001893
Neale Rannsb069a692017-03-15 12:34:25 -04001894 if (PREDICT_FALSE
1895 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1896 vnet_feature_arc_start (lm->output_feature_arc_index,
1897 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001898 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001899 else
1900 {
1901 p0->error = error_node->errors[error0];
1902 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001903 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1904 {
1905 p1->current_data -= rw_len1;
1906 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1909 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1910 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001911
Neale Rannsb069a692017-03-15 12:34:25 -04001912 if (PREDICT_FALSE
1913 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1914 vnet_feature_arc_start (lm->output_feature_arc_index,
1915 tx_sw_if_index1, &next1, p1);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001916 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04001917 else
1918 {
1919 p1->error = error_node->errors[error1];
1920 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921
Neale Ranns25edf142019-03-22 08:12:48 +00001922 if (is_midchain)
1923 {
1924 /* before we paint on the next header, update the L4
1925 * checksums if required, since there's no offload on a tunnel */
Dave Barach1bd2c012020-04-12 08:31:39 -04001926 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
1927 1 /* is_ip6 */ ,
1928 0 /* with gso */ );
1929 vnet_calc_checksums_inline (vm, p1, 0 /* is_ip4 */ ,
1930 1 /* is_ip6 */ ,
1931 0 /* with gso */ );
Neale Ranns25edf142019-03-22 08:12:48 +00001932 }
1933
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001934 /* Guess we are only writing on simple Ethernet header. */
1935 vnet_rewrite_two_headers (adj0[0], adj1[0],
1936 ip0, ip1, sizeof (ethernet_header_t));
1937
1938 if (is_midchain)
1939 {
Neale Ranns25edf142019-03-22 08:12:48 +00001940 if (adj0->sub_type.midchain.fixup_func)
1941 adj0->sub_type.midchain.fixup_func
1942 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1943 if (adj1->sub_type.midchain.fixup_func)
1944 adj1->sub_type.midchain.fixup_func
1945 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02001946 }
1947 if (is_mcast)
1948 {
1949 /*
1950 * copy bytes from the IP address into the MAC rewrite
1951 */
Neale Ranns889fe942017-06-01 05:43:19 -04001952 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1953 adj0->
1954 rewrite_header.dst_mcast_offset,
1955 &ip0->dst_address.as_u32[3],
1956 (u8 *) ip0);
1957 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1958 adj1->
1959 rewrite_header.dst_mcast_offset,
1960 &ip1->dst_address.as_u32[3],
1961 (u8 *) ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001962 }
Neale Ranns5e575b12016-10-03 09:40:25 +01001963
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1965 to_next, n_left_to_next,
1966 pi0, pi1, next0, next1);
1967 }
1968
1969 while (n_left_from > 0 && n_left_to_next > 0)
1970 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001971 ip_adjacency_t *adj0;
1972 vlib_buffer_t *p0;
1973 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974 u32 pi0, rw_len0;
1975 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001976 u32 tx_sw_if_index0;
Ole Troan313f7e22018-04-10 16:02:51 +02001977 bool is_locally_originated0;
Dave Barach75fc8542016-10-11 16:16:02 -04001978
Ed Warnickecb9cada2015-12-08 15:45:58 -07001979 pi0 = to_next[0] = from[0];
1980
1981 p0 = vlib_get_buffer (vm, pi0);
1982
Neale Rannsf06aea52016-11-29 06:51:37 -08001983 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001984
Neale Ranns107e7d42017-04-11 09:55:19 -07001985 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04001986
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987 ip0 = vlib_buffer_get_current (p0);
1988
1989 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001990 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001991
1992 /* Check hop limit */
Ole Troan313f7e22018-04-10 16:02:51 +02001993 is_locally_originated0 =
1994 p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1995 if (PREDICT_TRUE (!is_locally_originated0))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001996 {
1997 i32 hop_limit0 = ip0->hop_limit;
1998
1999 ASSERT (ip0->hop_limit > 0);
2000
2001 hop_limit0 -= 1;
2002
2003 ip0->hop_limit = hop_limit0;
2004
Dave Barachd7cb1b52016-12-09 09:52:16 -05002005 if (PREDICT_FALSE (hop_limit0 <= 0))
2006 {
2007 /*
2008 * If the hop count drops below 1 when forwarding, generate
2009 * an ICMP response.
2010 */
2011 error0 = IP6_ERROR_TIME_EXPIRED;
2012 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2013 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2014 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2015 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2016 0);
2017 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 }
2019
Neale Ranns25edf142019-03-22 08:12:48 +00002020 if (is_midchain)
2021 {
Dave Barach1bd2c012020-04-12 08:31:39 -04002022 vnet_calc_checksums_inline (vm, p0, 0 /* is_ip4 */ ,
2023 1 /* is_ip6 */ ,
2024 0 /* with gso */ );
Neale Ranns25edf142019-03-22 08:12:48 +00002025 }
2026
Ed Warnickecb9cada2015-12-08 15:45:58 -07002027 /* Guess we are only writing on simple Ethernet header. */
2028 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002029
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030 /* Update packet buffer attributes/set output interface. */
2031 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002032 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002033
Neale Ranns9c6a6132017-02-21 05:33:14 -08002034 if (do_counters)
2035 {
2036 vlib_increment_combined_counter
2037 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002038 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002039 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2040 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041
2042 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002043 u16 ip0_len =
2044 clib_net_to_host_u16 (ip0->payload_length) +
2045 sizeof (ip6_header_t);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002046 if (p0->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002047 ip0_len = gso_mtu_sz (p0);
2048
2049 ip6_mtu_check (p0, ip0_len,
Ole Troanda6e11b2018-05-23 11:21:42 +02002050 adj0[0].rewrite_header.max_l3_packet_bytes,
Ole Troaneb284a12019-10-09 13:33:19 +02002051 is_locally_originated0, &next0, is_midchain,
2052 &error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053
Dave Barachd7cb1b52016-12-09 09:52:16 -05002054 /* Don't adjust the buffer for hop count issue; icmp-error node
Ole Troanda6e11b2018-05-23 11:21:42 +02002055 * wants to see the IP header */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002056 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2057 {
Chris Luke816f3e12016-06-14 16:24:47 -04002058 p0->current_data -= rw_len0;
2059 p0->current_length += rw_len0;
2060
Dave Barachd7cb1b52016-12-09 09:52:16 -05002061 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002062
Dave Barachd7cb1b52016-12-09 09:52:16 -05002063 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2064 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002065
Neale Rannsb069a692017-03-15 12:34:25 -04002066 if (PREDICT_FALSE
2067 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2068 vnet_feature_arc_start (lm->output_feature_arc_index,
2069 tx_sw_if_index0, &next0, p0);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002070 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002071 else
2072 {
2073 p0->error = error_node->errors[error0];
2074 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002075
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002076 if (is_midchain)
2077 {
Neale Ranns25edf142019-03-22 08:12:48 +00002078 if (adj0->sub_type.midchain.fixup_func)
2079 adj0->sub_type.midchain.fixup_func
2080 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Damjan Marionfe7d4a22018-04-13 19:43:39 +02002081 }
2082 if (is_mcast)
2083 {
Neale Ranns889fe942017-06-01 05:43:19 -04002084 vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
2085 adj0->
2086 rewrite_header.dst_mcast_offset,
2087 &ip0->dst_address.as_u32[3],
2088 (u8 *) ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002089 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002090
Ed Warnickecb9cada2015-12-08 15:45:58 -07002091 from += 1;
2092 n_left_from -= 1;
2093 to_next += 1;
2094 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002095
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2097 to_next, n_left_to_next,
2098 pi0, next0);
2099 }
2100
2101 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2102 }
2103
2104 /* Need to do trace after rewrites to pick up new packet data. */
2105 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002106 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002107
2108 return frame->n_vectors;
2109}
2110
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002111always_inline uword
2112ip6_rewrite_inline (vlib_main_t * vm,
2113 vlib_node_runtime_t * node,
2114 vlib_frame_t * frame,
2115 int do_counters, int is_midchain, int is_mcast)
2116{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002117 return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2118 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002119}
2120
Damjan Marion38173502019-02-13 19:30:09 +01002121VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
2122 vlib_node_runtime_t * node,
2123 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002124{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002125 if (adj_are_counters_enabled ())
2126 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2127 else
2128 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002129}
2130
Damjan Marion38173502019-02-13 19:30:09 +01002131VLIB_NODE_FN (ip6_rewrite_bcast_node) (vlib_main_t * vm,
2132 vlib_node_runtime_t * node,
2133 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002134{
2135 if (adj_are_counters_enabled ())
2136 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2137 else
2138 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2139}
2140
Damjan Marion38173502019-02-13 19:30:09 +01002141VLIB_NODE_FN (ip6_rewrite_mcast_node) (vlib_main_t * vm,
2142 vlib_node_runtime_t * node,
2143 vlib_frame_t * frame)
Neale Ranns32e1c012016-11-22 17:07:28 +00002144{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002145 if (adj_are_counters_enabled ())
2146 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2147 else
2148 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149}
2150
Damjan Marion38173502019-02-13 19:30:09 +01002151VLIB_NODE_FN (ip6_midchain_node) (vlib_main_t * vm,
2152 vlib_node_runtime_t * node,
2153 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002154{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002155 if (adj_are_counters_enabled ())
2156 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2157 else
2158 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002159}
2160
Damjan Marion38173502019-02-13 19:30:09 +01002161VLIB_NODE_FN (ip6_mcast_midchain_node) (vlib_main_t * vm,
2162 vlib_node_runtime_t * node,
2163 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002164{
2165 if (adj_are_counters_enabled ())
2166 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2167 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002168 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002169}
2170
Dave Barachd7cb1b52016-12-09 09:52:16 -05002171/* *INDENT-OFF* */
2172VLIB_REGISTER_NODE (ip6_midchain_node) =
2173{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002174 .name = "ip6-midchain",
2175 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002176 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002177 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002178 };
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002179
Dave Barachd7cb1b52016-12-09 09:52:16 -05002180VLIB_REGISTER_NODE (ip6_rewrite_node) =
2181{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002182 .name = "ip6-rewrite",
2183 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002184 .format_trace = format_ip6_rewrite_trace,
Ole Troan313f7e22018-04-10 16:02:51 +02002185 .n_next_nodes = IP6_REWRITE_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002186 .next_nodes =
2187 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002188 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002189 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002190 [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002191 },
2192};
2193
Neale Ranns1855b8e2018-07-11 10:31:26 -07002194VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002195 .name = "ip6-rewrite-bcast",
2196 .vector_size = sizeof (u32),
2197
2198 .format_trace = format_ip6_rewrite_trace,
2199 .sibling_of = "ip6-rewrite",
2200};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002201
Neale Ranns32e1c012016-11-22 17:07:28 +00002202VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2203{
Neale Ranns32e1c012016-11-22 17:07:28 +00002204 .name = "ip6-rewrite-mcast",
2205 .vector_size = sizeof (u32),
2206 .format_trace = format_ip6_rewrite_trace,
2207 .sibling_of = "ip6-rewrite",
2208};
Neale Ranns32e1c012016-11-22 17:07:28 +00002209
Neale Ranns32e1c012016-11-22 17:07:28 +00002210
Damjan Marion38173502019-02-13 19:30:09 +01002211VLIB_REGISTER_NODE (ip6_mcast_midchain_node) =
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002212{
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002213 .name = "ip6-mcast-midchain",
2214 .vector_size = sizeof (u32),
2215 .format_trace = format_ip6_rewrite_trace,
2216 .sibling_of = "ip6-rewrite",
2217};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002218
Neale Ranns1855b8e2018-07-11 10:31:26 -07002219/* *INDENT-ON* */
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002220
Ole Troan944f5482016-05-24 11:56:58 +02002221/*
2222 * Hop-by-Hop handling
2223 */
Benoît Ganne47727c02019-02-12 13:35:08 +01002224#ifndef CLIB_MARCH_VARIANT
Ole Troan944f5482016-05-24 11:56:58 +02002225ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01002226#endif /* CLIB_MARCH_VARIANT */
Ole Troan944f5482016-05-24 11:56:58 +02002227
2228#define foreach_ip6_hop_by_hop_error \
2229_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2230_(FORMAT, "incorrectly formatted hop-by-hop options") \
2231_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2232
Neale Ranns32e1c012016-11-22 17:07:28 +00002233/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002234typedef enum
2235{
Ole Troan944f5482016-05-24 11:56:58 +02002236#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2237 foreach_ip6_hop_by_hop_error
2238#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002239 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002240} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002241/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002242
2243/*
2244 * Primary h-b-h handler trace support
2245 * We work pretty hard on the problem for obvious reasons
2246 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247typedef struct
2248{
Ole Troan944f5482016-05-24 11:56:58 +02002249 u32 next_index;
2250 u32 trace_len;
2251 u8 option_data[256];
2252} ip6_hop_by_hop_trace_t;
2253
Benoît Ganne47727c02019-02-12 13:35:08 +01002254extern vlib_node_registration_t ip6_hop_by_hop_node;
Ole Troan944f5482016-05-24 11:56:58 +02002255
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002257#define _(sym,string) string,
2258 foreach_ip6_hop_by_hop_error
2259#undef _
2260};
2261
Damjan Marion38173502019-02-13 19:30:09 +01002262#ifndef CLIB_MARCH_VARIANT
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302263u8 *
2264format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2265{
2266 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2267 int total_len = va_arg (*args, int);
2268 ip6_hop_by_hop_option_t *opt0, *limit0;
2269 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2270 u8 type0;
2271
2272 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2273 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2274
2275 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2276 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2277
2278 while (opt0 < limit0)
2279 {
2280 type0 = opt0->type;
2281 switch (type0)
2282 {
2283 case 0: /* Pad, just stop */
2284 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2285 break;
2286
2287 default:
2288 if (hm->trace[type0])
2289 {
2290 s = (*hm->trace[type0]) (s, opt0);
2291 }
2292 else
2293 {
2294 s =
2295 format (s, "\n unrecognized option %d length %d", type0,
2296 opt0->length);
2297 }
2298 opt0 =
2299 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2300 sizeof (ip6_hop_by_hop_option_t));
2301 break;
2302 }
2303 }
2304 return s;
2305}
Damjan Marion38173502019-02-13 19:30:09 +01002306#endif
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302307
Ole Troan944f5482016-05-24 11:56:58 +02002308static u8 *
2309format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2310{
2311 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2312 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002313 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002314 ip6_hop_by_hop_header_t *hbh0;
2315 ip6_hop_by_hop_option_t *opt0, *limit0;
2316 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2317
2318 u8 type0;
2319
Dave Barachd7cb1b52016-12-09 09:52:16 -05002320 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002321
2322 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002323 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002324
Dave Barachd7cb1b52016-12-09 09:52:16 -05002325 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2326 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002327
Dave Barachd7cb1b52016-12-09 09:52:16 -05002328 while (opt0 < limit0)
2329 {
2330 type0 = opt0->type;
2331 switch (type0)
2332 {
2333 case 0: /* Pad, just stop */
2334 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2335 break;
Ole Troan944f5482016-05-24 11:56:58 +02002336
Dave Barachd7cb1b52016-12-09 09:52:16 -05002337 default:
2338 if (hm->trace[type0])
2339 {
2340 s = (*hm->trace[type0]) (s, opt0);
2341 }
2342 else
2343 {
2344 s =
2345 format (s, "\n unrecognized option %d length %d", type0,
2346 opt0->length);
2347 }
2348 opt0 =
2349 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2350 sizeof (ip6_hop_by_hop_option_t));
2351 break;
2352 }
Ole Troan944f5482016-05-24 11:56:58 +02002353 }
Ole Troan944f5482016-05-24 11:56:58 +02002354 return s;
2355}
2356
Dave Barachd7cb1b52016-12-09 09:52:16 -05002357always_inline u8
2358ip6_scan_hbh_options (vlib_buffer_t * b0,
2359 ip6_header_t * ip0,
2360 ip6_hop_by_hop_header_t * hbh0,
2361 ip6_hop_by_hop_option_t * opt0,
2362 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002363{
2364 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2365 u8 type0;
2366 u8 error0 = 0;
2367
2368 while (opt0 < limit0)
2369 {
2370 type0 = opt0->type;
2371 switch (type0)
2372 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002373 case 0: /* Pad1 */
2374 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002375 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002376 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002377 break;
2378 default:
2379 if (hm->options[type0])
2380 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002381 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2382 {
Shwethaa91cbe62016-08-08 15:51:04 +01002383 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002384 return (error0);
2385 }
Shwethaa91cbe62016-08-08 15:51:04 +01002386 }
2387 else
2388 {
2389 /* Unrecognized mandatory option, check the two high order bits */
2390 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2391 {
2392 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2393 break;
2394 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2395 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2396 *next0 = IP_LOOKUP_NEXT_DROP;
2397 break;
2398 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2399 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2400 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002401 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2402 ICMP6_parameter_problem_unrecognized_option,
2403 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002404 break;
2405 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2406 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002407 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002408 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002409 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2410 icmp6_error_set_vnet_buffer (b0,
2411 ICMP6_parameter_problem,
2412 ICMP6_parameter_problem_unrecognized_option,
2413 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002414 }
2415 else
2416 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002417 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002418 }
2419 break;
2420 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002421 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002422 }
2423 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002424 opt0 =
2425 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2426 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002427 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002429}
2430
Ole Troan944f5482016-05-24 11:56:58 +02002431/*
2432 * Process the Hop-by-Hop Options header
2433 */
Damjan Marion38173502019-02-13 19:30:09 +01002434VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
2435 vlib_node_runtime_t * node,
2436 vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002437{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002438 vlib_node_runtime_t *error_node =
2439 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002440 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2441 u32 n_left_from, *from, *to_next;
2442 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002443
2444 from = vlib_frame_vector_args (frame);
2445 n_left_from = frame->n_vectors;
2446 next_index = node->cached_next_index;
2447
Dave Barachd7cb1b52016-12-09 09:52:16 -05002448 while (n_left_from > 0)
2449 {
2450 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002451
Dave Barachd7cb1b52016-12-09 09:52:16 -05002452 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002453
Dave Barachd7cb1b52016-12-09 09:52:16 -05002454 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002455 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002456 u32 bi0, bi1;
2457 vlib_buffer_t *b0, *b1;
2458 u32 next0, next1;
2459 ip6_header_t *ip0, *ip1;
2460 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2461 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2462 u8 error0 = 0, error1 = 0;
2463
2464 /* Prefetch next iteration. */
2465 {
2466 vlib_buffer_t *p2, *p3;
2467
2468 p2 = vlib_get_buffer (vm, from[2]);
2469 p3 = vlib_get_buffer (vm, from[3]);
2470
2471 vlib_prefetch_buffer_header (p2, LOAD);
2472 vlib_prefetch_buffer_header (p3, LOAD);
2473
2474 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2475 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002476 }
2477
Dave Barachd7cb1b52016-12-09 09:52:16 -05002478 /* Speculatively enqueue b0, b1 to the current next frame */
2479 to_next[0] = bi0 = from[0];
2480 to_next[1] = bi1 = from[1];
2481 from += 2;
2482 to_next += 2;
2483 n_left_from -= 2;
2484 n_left_to_next -= 2;
2485
2486 b0 = vlib_get_buffer (vm, bi0);
2487 b1 = vlib_get_buffer (vm, bi1);
2488
2489 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2490 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002491 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002492 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002493 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002494
2495 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2496 next0 = adj0->lookup_next_index;
2497 next1 = adj1->lookup_next_index;
2498
2499 ip0 = vlib_buffer_get_current (b0);
2500 ip1 = vlib_buffer_get_current (b1);
2501 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2502 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2503 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2504 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2505 limit0 =
2506 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2507 ((hbh0->length + 1) << 3));
2508 limit1 =
2509 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2510 ((hbh1->length + 1) << 3));
2511
2512 /*
2513 * Basic validity checks
2514 */
2515 if ((hbh0->length + 1) << 3 >
2516 clib_net_to_host_u16 (ip0->payload_length))
2517 {
2518 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2519 next0 = IP_LOOKUP_NEXT_DROP;
2520 goto outdual;
2521 }
2522 /* Scan the set of h-b-h options, process ones that we understand */
2523 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2524
2525 if ((hbh1->length + 1) << 3 >
2526 clib_net_to_host_u16 (ip1->payload_length))
2527 {
2528 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2529 next1 = IP_LOOKUP_NEXT_DROP;
2530 goto outdual;
2531 }
2532 /* Scan the set of h-b-h options, process ones that we understand */
2533 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2534
2535 outdual:
2536 /* Has the classifier flagged this buffer for special treatment? */
2537 if (PREDICT_FALSE
2538 ((error0 == 0)
2539 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2540 next0 = hm->next_override;
2541
2542 /* Has the classifier flagged this buffer for special treatment? */
2543 if (PREDICT_FALSE
2544 ((error1 == 0)
2545 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2546 next1 = hm->next_override;
2547
2548 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2549 {
2550 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2551 {
2552 ip6_hop_by_hop_trace_t *t =
2553 vlib_add_trace (vm, node, b0, sizeof (*t));
2554 u32 trace_len = (hbh0->length + 1) << 3;
2555 t->next_index = next0;
2556 /* Capture the h-b-h option verbatim */
2557 trace_len =
2558 trace_len <
2559 ARRAY_LEN (t->option_data) ? trace_len :
2560 ARRAY_LEN (t->option_data);
2561 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002562 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563 }
2564 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2565 {
2566 ip6_hop_by_hop_trace_t *t =
2567 vlib_add_trace (vm, node, b1, sizeof (*t));
2568 u32 trace_len = (hbh1->length + 1) << 3;
2569 t->next_index = next1;
2570 /* Capture the h-b-h option verbatim */
2571 trace_len =
2572 trace_len <
2573 ARRAY_LEN (t->option_data) ? trace_len :
2574 ARRAY_LEN (t->option_data);
2575 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002576 clib_memcpy_fast (t->option_data, hbh1, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002577 }
2578
2579 }
2580
2581 b0->error = error_node->errors[error0];
2582 b1->error = error_node->errors[error1];
2583
2584 /* verify speculative enqueue, maybe switch current next frame */
2585 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2586 n_left_to_next, bi0, bi1, next0,
2587 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002588 }
2589
Dave Barachd7cb1b52016-12-09 09:52:16 -05002590 while (n_left_from > 0 && n_left_to_next > 0)
2591 {
2592 u32 bi0;
2593 vlib_buffer_t *b0;
2594 u32 next0;
2595 ip6_header_t *ip0;
2596 ip6_hop_by_hop_header_t *hbh0;
2597 ip6_hop_by_hop_option_t *opt0, *limit0;
2598 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002599
Dave Barachd7cb1b52016-12-09 09:52:16 -05002600 /* Speculatively enqueue b0 to the current next frame */
2601 bi0 = from[0];
2602 to_next[0] = bi0;
2603 from += 1;
2604 to_next += 1;
2605 n_left_from -= 1;
2606 n_left_to_next -= 1;
2607
2608 b0 = vlib_get_buffer (vm, bi0);
2609 /*
2610 * Default use the next_index from the adjacency.
2611 * A HBH option rarely redirects to a different node
2612 */
2613 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002614 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002615 next0 = adj0->lookup_next_index;
2616
2617 ip0 = vlib_buffer_get_current (b0);
2618 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2619 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2620 limit0 =
2621 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2622 ((hbh0->length + 1) << 3));
2623
2624 /*
2625 * Basic validity checks
2626 */
2627 if ((hbh0->length + 1) << 3 >
2628 clib_net_to_host_u16 (ip0->payload_length))
2629 {
2630 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2631 next0 = IP_LOOKUP_NEXT_DROP;
2632 goto out0;
2633 }
2634
2635 /* Scan the set of h-b-h options, process ones that we understand */
2636 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2637
2638 out0:
2639 /* Has the classifier flagged this buffer for special treatment? */
2640 if (PREDICT_FALSE
2641 ((error0 == 0)
2642 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2643 next0 = hm->next_override;
2644
2645 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2646 {
2647 ip6_hop_by_hop_trace_t *t =
2648 vlib_add_trace (vm, node, b0, sizeof (*t));
2649 u32 trace_len = (hbh0->length + 1) << 3;
2650 t->next_index = next0;
2651 /* Capture the h-b-h option verbatim */
2652 trace_len =
2653 trace_len <
2654 ARRAY_LEN (t->option_data) ? trace_len :
2655 ARRAY_LEN (t->option_data);
2656 t->trace_len = trace_len;
Dave Barach178cf492018-11-13 16:34:13 -05002657 clib_memcpy_fast (t->option_data, hbh0, trace_len);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002658 }
2659
2660 b0->error = error_node->errors[error0];
2661
2662 /* verify speculative enqueue, maybe switch current next frame */
2663 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2664 n_left_to_next, bi0, next0);
2665 }
2666 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002667 }
Ole Troan944f5482016-05-24 11:56:58 +02002668 return frame->n_vectors;
2669}
2670
Dave Barachd7cb1b52016-12-09 09:52:16 -05002671/* *INDENT-OFF* */
2672VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2673{
Ole Troan944f5482016-05-24 11:56:58 +02002674 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002675 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002676 .vector_size = sizeof (u32),
2677 .format_trace = format_ip6_hop_by_hop_trace,
2678 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002679 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002680 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002681 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002682};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002684
Ole Troan944f5482016-05-24 11:56:58 +02002685static clib_error_t *
2686ip6_hop_by_hop_init (vlib_main_t * vm)
2687{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002688 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Dave Barachb7b92992018-10-17 10:38:51 -04002689 clib_memset (hm->options, 0, sizeof (hm->options));
2690 clib_memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002691 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002692 return (0);
2693}
2694
2695VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2696
Damjan Marion38173502019-02-13 19:30:09 +01002697#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002698void
2699ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002700{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002701 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002702
2703 hm->next_override = next;
2704}
2705
Ole Troan944f5482016-05-24 11:56:58 +02002706int
2707ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002708 int options (vlib_buffer_t * b, ip6_header_t * ip,
2709 ip6_hop_by_hop_option_t * opt),
2710 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002711{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002712 ip6_main_t *im = &ip6_main;
2713 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002714
Neale Ranns756cd942018-04-06 09:18:11 -07002715 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002716
2717 /* Already registered */
2718 if (hm->options[option])
2719 return (-1);
2720
2721 hm->options[option] = options;
2722 hm->trace[option] = trace;
2723
2724 /* Set global variable */
2725 im->hbh_enabled = 1;
2726
2727 return (0);
2728}
2729
2730int
2731ip6_hbh_unregister_option (u8 option)
2732{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002733 ip6_main_t *im = &ip6_main;
2734 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002735
Neale Ranns756cd942018-04-06 09:18:11 -07002736 ASSERT ((u32) option < ARRAY_LEN (hm->options));
Ole Troan944f5482016-05-24 11:56:58 +02002737
2738 /* Not registered */
2739 if (!hm->options[option])
2740 return (-1);
2741
2742 hm->options[option] = NULL;
2743 hm->trace[option] = NULL;
2744
2745 /* Disable global knob if this was the last option configured */
2746 int i;
2747 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002748 for (i = 0; i < 256; i++)
2749 {
2750 if (hm->options[option])
2751 {
2752 found = true;
2753 break;
2754 }
Ole Troan944f5482016-05-24 11:56:58 +02002755 }
Ole Troan944f5482016-05-24 11:56:58 +02002756 if (!found)
2757 im->hbh_enabled = 0;
2758
2759 return (0);
2760}
2761
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762/* Global IP6 main. */
2763ip6_main_t ip6_main;
Damjan Marion38173502019-02-13 19:30:09 +01002764#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002765
2766static clib_error_t *
2767ip6_lookup_init (vlib_main_t * vm)
2768{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002769 ip6_main_t *im = &ip6_main;
2770 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002771 uword i;
2772
Damjan Marion8b3191e2016-11-09 19:54:20 +01002773 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2774 return error;
2775
Ed Warnickecb9cada2015-12-08 15:45:58 -07002776 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2777 {
2778 u32 j, i0, i1;
2779
2780 i0 = i / 32;
2781 i1 = i % 32;
2782
2783 for (j = 0; j < i0; j++)
2784 im->fib_masks[i].as_u32[j] = ~0;
2785
2786 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002787 im->fib_masks[i].as_u32[i0] =
2788 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002789 }
2790
2791 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2792
2793 if (im->lookup_table_nbuckets == 0)
2794 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2795
Dave Barachd7cb1b52016-12-09 09:52:16 -05002796 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002797
2798 if (im->lookup_table_size == 0)
2799 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002800
Neale Rannsae809832018-11-23 09:00:27 -08002801 clib_bihash_init_24_8 (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
Dave Barachd7cb1b52016-12-09 09:52:16 -05002802 "ip6 FIB fwding table",
2803 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Rannsae809832018-11-23 09:00:27 -08002804 clib_bihash_init_24_8 (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002805 "ip6 FIB non-fwding table",
2806 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Rannsae809832018-11-23 09:00:27 -08002807 clib_bihash_init_40_8 (&im->ip6_mtable.ip6_mhash,
2808 "ip6 mFIB table",
2809 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002810
Ed Warnickecb9cada2015-12-08 15:45:58 -07002811 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07002812 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2813 FIB_SOURCE_DEFAULT_ROUTE);
2814 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2815 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002816
2817 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002818 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002819 pn = pg_get_node (ip6_lookup_node.index);
2820 pn->unformat_edit = unformat_pg_ip6_header;
2821 }
2822
Ole Troan944f5482016-05-24 11:56:58 +02002823 /* Unless explicitly configured, don't process HBH options */
2824 im->hbh_enabled = 0;
2825
Dave Barach203c6322016-06-26 10:29:03 -04002826 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002827}
2828
2829VLIB_INIT_FUNCTION (ip6_lookup_init);
2830
Damjan Marion38173502019-02-13 19:30:09 +01002831#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002832int
2833vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002834{
Neale Ranns107e7d42017-04-11 09:55:19 -07002835 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002836
Neale Ranns107e7d42017-04-11 09:55:19 -07002837 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002838
Neale Ranns107e7d42017-04-11 09:55:19 -07002839 if (~0 == fib_index)
2840 return VNET_API_ERROR_NO_SUCH_FIB;
2841
Neale Ranns227038a2017-04-21 01:07:59 -07002842 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
2843 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002844
Neale Ranns227038a2017-04-21 01:07:59 -07002845 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002846}
Damjan Marion38173502019-02-13 19:30:09 +01002847#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002848
2849static clib_error_t *
2850set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002851 unformat_input_t * input,
2852 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002853{
2854 int matched = 0;
2855 u32 table_id = 0;
2856 u32 flow_hash_config = 0;
2857 int rv;
2858
Dave Barachd7cb1b52016-12-09 09:52:16 -05002859 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2860 {
2861 if (unformat (input, "table %d", &table_id))
2862 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002863#define _(a,v) \
2864 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002865 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002867 else
2868 break;
2869 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002870
2871 if (matched == 0)
2872 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002873 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002874
Ed Warnickecb9cada2015-12-08 15:45:58 -07002875 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
2876 switch (rv)
2877 {
Neale Ranns227038a2017-04-21 01:07:59 -07002878 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879 break;
2880
2881 case -1:
2882 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002883
Ed Warnickecb9cada2015-12-08 15:45:58 -07002884 default:
2885 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2886 break;
2887 }
Dave Barach75fc8542016-10-11 16:16:02 -04002888
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889 return 0;
2890}
2891
Billy McFall0683c9c2016-10-13 08:27:31 -04002892/*?
2893 * Configure the set of IPv6 fields used by the flow hash.
2894 *
2895 * @cliexpar
2896 * @parblock
2897 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04002898 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2899 *
Billy McFall0683c9c2016-10-13 08:27:31 -04002900 * Example of display the configured flow hash:
2901 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002902 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2903 * @::/0
2904 * unicast-ip6-chain
2905 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2906 * [0] [@0]: dpo-drop ip6
2907 * fe80::/10
2908 * unicast-ip6-chain
2909 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2910 * [0] [@2]: dpo-receive
2911 * ff02::1/128
2912 * unicast-ip6-chain
2913 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2914 * [0] [@2]: dpo-receive
2915 * ff02::2/128
2916 * unicast-ip6-chain
2917 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2918 * [0] [@2]: dpo-receive
2919 * ff02::16/128
2920 * unicast-ip6-chain
2921 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2922 * [0] [@2]: dpo-receive
2923 * ff02::1:ff00:0/104
2924 * unicast-ip6-chain
2925 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2926 * [0] [@2]: dpo-receive
2927 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2928 * @::/0
2929 * unicast-ip6-chain
2930 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2931 * [0] [@0]: dpo-drop ip6
2932 * @::a:1:1:0:4/126
2933 * unicast-ip6-chain
2934 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2935 * [0] [@4]: ipv6-glean: af_packet0
2936 * @::a:1:1:0:7/128
2937 * unicast-ip6-chain
2938 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2939 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2940 * fe80::/10
2941 * unicast-ip6-chain
2942 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2943 * [0] [@2]: dpo-receive
2944 * fe80::fe:3eff:fe3e:9222/128
2945 * unicast-ip6-chain
2946 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2947 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2948 * ff02::1/128
2949 * unicast-ip6-chain
2950 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2951 * [0] [@2]: dpo-receive
2952 * ff02::2/128
2953 * unicast-ip6-chain
2954 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2955 * [0] [@2]: dpo-receive
2956 * ff02::16/128
2957 * unicast-ip6-chain
2958 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2959 * [0] [@2]: dpo-receive
2960 * ff02::1:ff00:0/104
2961 * unicast-ip6-chain
2962 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2963 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04002964 * @cliexend
2965 * @endparblock
2966?*/
2967/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002968VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
2969{
2970 .path = "set ip6 flow-hash",
2971 .short_help =
2972 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2973 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002974};
Billy McFall0683c9c2016-10-13 08:27:31 -04002975/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002976
2977static clib_error_t *
2978show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002979 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002981 ip6_main_t *im = &ip6_main;
2982 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002983 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04002984
Ed Warnickecb9cada2015-12-08 15:45:58 -07002985 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05002986 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987 {
2988 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02002989 {
2990
2991 u32 node_index = vlib_get_node (vm,
2992 ip6_local_node.index)->
2993 next_nodes[lm->local_next_by_ip_protocol[i]];
2994 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2995 node_index);
2996 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997 }
2998 return 0;
2999}
3000
3001
3002
Billy McFall0683c9c2016-10-13 08:27:31 -04003003/*?
3004 * Display the set of protocols handled by the local IPv6 stack.
3005 *
3006 * @cliexpar
3007 * Example of how to display local protocol table:
3008 * @cliexstart{show ip6 local}
3009 * Protocols handled by ip6_local
3010 * 17
3011 * 43
3012 * 58
3013 * 115
3014 * @cliexend
3015?*/
3016/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003017VLIB_CLI_COMMAND (show_ip6_local, static) =
3018{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019 .path = "show ip6 local",
3020 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003021 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022};
Billy McFall0683c9c2016-10-13 08:27:31 -04003023/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024
Damjan Marion38173502019-02-13 19:30:09 +01003025#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003026int
3027vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3028 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003029{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003030 vnet_main_t *vnm = vnet_get_main ();
3031 vnet_interface_main_t *im = &vnm->interface_main;
3032 ip6_main_t *ipm = &ip6_main;
3033 ip_lookup_main_t *lm = &ipm->lookup_main;
3034 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003035 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003036
3037 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3038 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3039
3040 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3041 return VNET_API_ERROR_NO_SUCH_ENTRY;
3042
3043 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003044 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003046 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003047
3048 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003049 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003050 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003051 .fp_len = 128,
3052 .fp_proto = FIB_PROTOCOL_IP6,
3053 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003054 };
3055 u32 fib_index;
3056
Dave Barachd7cb1b52016-12-09 09:52:16 -05003057 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3058 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003059
3060
Dave Barachd7cb1b52016-12-09 09:52:16 -05003061 if (table_index != (u32) ~ 0)
3062 {
3063 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003064
Dave Barachd7cb1b52016-12-09 09:52:16 -05003065 dpo_set (&dpo,
3066 DPO_CLASSIFY,
3067 DPO_PROTO_IP6,
3068 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003069
Dave Barachd7cb1b52016-12-09 09:52:16 -05003070 fib_table_entry_special_dpo_add (fib_index,
3071 &pfx,
3072 FIB_SOURCE_CLASSIFY,
3073 FIB_ENTRY_FLAG_NONE, &dpo);
3074 dpo_reset (&dpo);
3075 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003076 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003077 {
3078 fib_table_entry_special_remove (fib_index,
3079 &pfx, FIB_SOURCE_CLASSIFY);
3080 }
3081 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003082
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083 return 0;
3084}
Damjan Marion38173502019-02-13 19:30:09 +01003085#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003086
3087static clib_error_t *
3088set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089 unformat_input_t * input,
3090 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091{
3092 u32 table_index = ~0;
3093 int table_index_set = 0;
3094 u32 sw_if_index = ~0;
3095 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003096
Dave Barachd7cb1b52016-12-09 09:52:16 -05003097 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3098 {
3099 if (unformat (input, "table-index %d", &table_index))
3100 table_index_set = 1;
3101 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3102 vnet_get_main (), &sw_if_index))
3103 ;
3104 else
3105 break;
3106 }
Dave Barach75fc8542016-10-11 16:16:02 -04003107
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003109 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003110
Ed Warnickecb9cada2015-12-08 15:45:58 -07003111 if (sw_if_index == ~0)
3112 return clib_error_return (0, "interface / subif must be specified");
3113
3114 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3115
3116 switch (rv)
3117 {
3118 case 0:
3119 break;
3120
3121 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3122 return clib_error_return (0, "No such interface");
3123
3124 case VNET_API_ERROR_NO_SUCH_ENTRY:
3125 return clib_error_return (0, "No such classifier table");
3126 }
3127 return 0;
3128}
3129
Billy McFall0683c9c2016-10-13 08:27:31 -04003130/*?
3131 * Assign a classification table to an interface. The classification
3132 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3133 * commands. Once the table is create, use this command to filter packets
3134 * on an interface.
3135 *
3136 * @cliexpar
3137 * Example of how to assign a classification table to an interface:
3138 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3139?*/
3140/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003141VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3142{
3143 .path = "set ip6 classify",
3144 .short_help =
3145 "set ip6 classify intfc <interface> table-index <classify-idx>",
3146 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003147};
Billy McFall0683c9c2016-10-13 08:27:31 -04003148/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149
3150static clib_error_t *
3151ip6_config (vlib_main_t * vm, unformat_input_t * input)
3152{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003153 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003154 uword heapsize = 0;
3155 u32 tmp;
3156 u32 nbuckets = 0;
3157
Dave Barachd7cb1b52016-12-09 09:52:16 -05003158 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3159 {
3160 if (unformat (input, "hash-buckets %d", &tmp))
3161 nbuckets = tmp;
Neale Ranns1ec36522017-11-29 05:20:37 -08003162 else if (unformat (input, "heap-size %U",
3163 unformat_memory_size, &heapsize))
3164 ;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003165 else
3166 return clib_error_return (0, "unknown input '%U'",
3167 format_unformat_error, input);
3168 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003169
3170 im->lookup_table_nbuckets = nbuckets;
3171 im->lookup_table_size = heapsize;
3172
3173 return 0;
3174}
3175
3176VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003177
3178/*
3179 * fd.io coding-style-patch-verification: ON
3180 *
3181 * Local Variables:
3182 * eval: (c-set-style "gnu")
3183 * End:
3184 */