blob: 88b21d59019aa9eb0a86f0744c6f45129e61f813 [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>
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +020042#include <vnet/ip/ip6_neighbor.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
45#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053046#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000048#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070049#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/bihash_template.c>
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080053#include <vnet/ip/ip6_forward.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053055/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
56#define OI_DECAP 0x80000000
57
Ed Warnickecb9cada2015-12-08 15:45:58 -070058static void
59ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
60 ip6_main_t * im, u32 fib_index,
61 ip_interface_address_t * a)
62{
Dave Barachd7cb1b52016-12-09 09:52:16 -050063 ip_lookup_main_t *lm = &im->lookup_main;
64 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010065 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -050066 .fp_len = a->address_length,
67 .fp_proto = FIB_PROTOCOL_IP6,
68 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +010069 };
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Ed Warnickecb9cada2015-12-08 15:45:58 -070071 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -050072 {
Neale Ranns7a272742017-05-30 02:08:14 -070073 fib_table_entry_update_one_path (fib_index,
74 &pfx,
75 FIB_SOURCE_INTERFACE,
76 (FIB_ENTRY_FLAG_CONNECTED |
77 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -070078 DPO_PROTO_IP6,
Neale Ranns7a272742017-05-30 02:08:14 -070079 /* No next-hop address */
80 NULL, sw_if_index,
81 /* invalid FIB index */
82 ~0, 1,
83 /* no label stack */
84 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Neale Ranns0bfe5d82016-08-25 15:29:12 +010087 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -050089 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -050091 lm->classify_table_index_by_sw_if_index[sw_if_index];
92 if (classify_table_index != (u32) ~ 0)
93 {
94 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010095
Dave Barachd7cb1b52016-12-09 09:52:16 -050096 dpo_set (&dpo,
97 DPO_CLASSIFY,
98 DPO_PROTO_IP6,
99 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100100
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101 fib_table_entry_special_dpo_add (fib_index,
102 &pfx,
103 FIB_SOURCE_CLASSIFY,
104 FIB_ENTRY_FLAG_NONE, &dpo);
105 dpo_reset (&dpo);
106 }
107 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100108
Neale Rannsf12a83f2017-04-18 09:09:40 -0700109 fib_table_entry_update_one_path (fib_index, &pfx,
110 FIB_SOURCE_INTERFACE,
111 (FIB_ENTRY_FLAG_CONNECTED |
112 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700113 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700114 &pfx.fp_addr,
115 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500116 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117}
118
119static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100120ip6_del_interface_routes (ip6_main_t * im,
121 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500122 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500124 fib_prefix_t pfx = {
125 .fp_len = address_length,
126 .fp_proto = FIB_PROTOCOL_IP6,
127 .fp_addr.ip6 = *address,
128 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129
Dave Barachd7cb1b52016-12-09 09:52:16 -0500130 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 }
135
Dave Barachd7cb1b52016-12-09 09:52:16 -0500136 pfx.fp_len = 128;
137 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138}
139
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100140void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500141ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100142{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500143 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100145 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100147 /*
148 * enable/disable only on the 1<->0 transition
149 */
150 if (is_enable)
151 {
152 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500153 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100154 }
155 else
156 {
Neale Ranns75152282017-01-09 01:00:45 -0800157 /* The ref count is 0 when an address is removed from an interface that has
158 * no address - this is not a ciritical error */
159 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
160 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500161 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100162 }
163
Neale Ranns8269d3d2018-01-30 09:02:20 -0800164 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Neale Ranns630198f2017-05-22 09:20:20 -0400165 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100166
Neale Ranns8269d3d2018-01-30 09:02:20 -0800167 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
168 sw_if_index, !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100169}
170
Neale Rannsdf089a82016-10-02 16:39:06 +0100171/* get first interface address */
172ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800173ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100174{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500175 ip_lookup_main_t *lm = &im->lookup_main;
176 ip_interface_address_t *ia = 0;
177 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100178
Dave Barachd7cb1b52016-12-09 09:52:16 -0500179 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100180 foreach_ip_interface_address (lm, ia, sw_if_index,
181 1 /* honor unnumbered */,
182 ({
183 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
184 result = a;
185 break;
186 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100188 return result;
189}
190
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100191clib_error_t *
192ip6_add_del_interface_address (vlib_main_t * vm,
193 u32 sw_if_index,
194 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500195 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 vnet_main_t *vnm = vnet_get_main ();
198 ip6_main_t *im = &ip6_main;
199 ip_lookup_main_t *lm = &im->lookup_main;
200 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500202 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203
Pavel Kotucek57808982017-08-02 08:20:19 +0200204 /* local0 interface doesn't support IP addressing */
205 if (sw_if_index == 0)
206 {
207 return
208 clib_error_create ("local0 interface doesn't support IP addressing");
209 }
210
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000212 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
213
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 ip6_addr_fib_init (&ip6_af, address,
215 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
216 vec_add1 (addr_fib, ip6_af);
217
218 {
219 uword elts_before = pool_elts (lm->if_address_pool);
220
221 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500222 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 if (error)
224 goto done;
225
226 /* Pool did not grow: add duplicate address. */
227 if (elts_before == pool_elts (lm->if_address_pool))
228 goto done;
229 }
230
Dave Barachd7cb1b52016-12-09 09:52:16 -0500231 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000232
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100233 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500234 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100235 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500236 ip6_add_interface_routes (vnm, sw_if_index,
237 im, ip6_af.fib_index,
238 pool_elt_at_index (lm->if_address_pool,
239 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240
241 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500242 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 vec_foreach (cb, im->add_del_interface_address_callbacks)
244 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500245 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 }
247
Dave Barachd7cb1b52016-12-09 09:52:16 -0500248done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 vec_free (addr_fib);
250 return error;
251}
252
253clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500254ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500256 ip6_main_t *im = &ip6_main;
257 ip_interface_address_t *ia;
258 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259 u32 is_admin_up, fib_index;
260
261 /* Fill in lookup tables with default table (0). */
262 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
263
Dave Barachd7cb1b52016-12-09 09:52:16 -0500264 vec_validate_init_empty (im->
265 lookup_main.if_address_pool_index_by_sw_if_index,
266 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
268 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
269
270 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
271
Dave Barachd7cb1b52016-12-09 09:52:16 -0500272 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400273 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 0 /* honor unnumbered */,
275 ({
276 a = ip_interface_address_get_address (&im->lookup_main, ia);
277 if (is_admin_up)
278 ip6_add_interface_routes (vnm, sw_if_index,
279 im, fib_index,
280 ia);
281 else
282 ip6_del_interface_routes (im, fib_index,
283 a, ia->address_length);
284 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
287 return 0;
288}
289
290VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
291
Dave Barachd6534602016-06-14 18:38:02 -0400292/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100294VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
295{
296 .arc_name = "ip6-unicast",
297 .start_nodes = VNET_FEATURES ("ip6-input"),
298 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
299};
300
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301VNET_FEATURE_INIT (ip6_flow_classify, static) =
302{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100303 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700304 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100305 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700306};
307
Dave Barachd7cb1b52016-12-09 09:52:16 -0500308VNET_FEATURE_INIT (ip6_inacl, static) =
309{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100310 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400311 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100312 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400313};
314
Dave Barachd7cb1b52016-12-09 09:52:16 -0500315VNET_FEATURE_INIT (ip6_policer_classify, static) =
316{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100317 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700318 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100319 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700320};
321
Dave Barachd7cb1b52016-12-09 09:52:16 -0500322VNET_FEATURE_INIT (ip6_ipsec, static) =
323{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100324 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400325 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100326 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400327};
328
Dave Barachd7cb1b52016-12-09 09:52:16 -0500329VNET_FEATURE_INIT (ip6_l2tp, static) =
330{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100331 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400332 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100333 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400334};
335
Dave Barachd7cb1b52016-12-09 09:52:16 -0500336VNET_FEATURE_INIT (ip6_vpath, static) =
337{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100338 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400339 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500340 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
341};
342
343VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
344{
345 .arc_name = "ip6-unicast",
346 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100347 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400348};
349
Neale Ranns8269d3d2018-01-30 09:02:20 -0800350VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500351{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100352 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800353 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400354 .runs_before = VNET_FEATURES ("ip6-lookup"),
355};
356
357VNET_FEATURE_INIT (ip6_lookup, static) =
358{
359 .arc_name = "ip6-unicast",
360 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100361 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362};
363
Dave Barachd6534602016-06-14 18:38:02 -0400364/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100365VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
366{
367 .arc_name = "ip6-multicast",
368 .start_nodes = VNET_FEATURES ("ip6-input"),
369 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
370};
371
372VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
373 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400374 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000375 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400376};
377
Neale Ranns8269d3d2018-01-30 09:02:20 -0800378VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100379 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800380 .node_name = "ip6-not-enabled",
Neale Ranns630198f2017-05-22 09:20:20 -0400381 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
382};
383
384VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
385 .arc_name = "ip6-multicast",
386 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100387 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100388};
Dave Barach5331c722016-08-17 11:54:30 -0400389
390/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100391VNET_FEATURE_ARC_INIT (ip6_output, static) =
392{
393 .arc_name = "ip6-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800394 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Damjan Marion8b3191e2016-11-09 19:54:20 +0100395 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400396};
397
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +0100398VNET_FEATURE_INIT (ip6_outacl, static) = {
399 .arc_name = "ip6-output",
400 .node_name = "ip6-outacl",
401 .runs_before = VNET_FEATURES ("ipsec-output-ip6"),
402};
403
Matus Fabian08a6f012016-11-15 06:08:51 -0800404VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
405 .arc_name = "ip6-output",
406 .node_name = "ipsec-output-ip6",
407 .runs_before = VNET_FEATURES ("interface-output"),
408};
409
Damjan Marion8b3191e2016-11-09 19:54:20 +0100410VNET_FEATURE_INIT (ip6_interface_output, static) = {
411 .arc_name = "ip6-output",
412 .node_name = "interface-output",
413 .runs_before = 0, /* not before any other features */
414};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500415/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400416
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500418ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700420 ip6_main_t *im = &ip6_main;
421
422 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
423 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
424
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200425 if (!is_add)
426 {
427 /* Ensure that IPv6 is disabled */
428 ip6_main_t *im6 = &ip6_main;
429 ip_lookup_main_t *lm6 = &im6->lookup_main;
430 ip_interface_address_t *ia = 0;
431 ip6_address_t *address;
432 vlib_main_t *vm = vlib_get_main ();
433
434 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700435 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200436 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -0700437 foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200438 ({
439 address = ip_interface_address_get_address (lm6, ia);
440 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
441 }));
442 /* *INDENT-ON* */
443 ip6_mfib_interface_enable_disable (sw_if_index, 0);
444 }
445
Neale Ranns8269d3d2018-01-30 09:02:20 -0800446 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100447 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448
Neale Ranns8269d3d2018-01-30 09:02:20 -0800449 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
450 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452 return /* no error */ 0;
453}
454
455VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
456
Damjan Marionaca64c92016-04-13 09:48:56 +0200457static uword
458ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500459 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200460{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100461 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200462}
463
Dave Barachd7cb1b52016-12-09 09:52:16 -0500464static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100465
Dave Barachd7cb1b52016-12-09 09:52:16 -0500466/* *INDENT-OFF* */
467VLIB_REGISTER_NODE (ip6_lookup_node) =
468{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 .function = ip6_lookup,
470 .name = "ip6-lookup",
471 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100472 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200473 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200474 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500476/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477
Dave Barachd7cb1b52016-12-09 09:52:16 -0500478VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200479
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100480always_inline uword
481ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200483{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500484 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
485 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100486 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200487 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500488 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100489
490 from = vlib_frame_vector_args (frame);
491 n_left_from = frame->n_vectors;
492 next = node->cached_next_index;
493
494 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500495 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100496
497 while (n_left_from > 0)
498 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500499 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100500
Dave Barach75fc8542016-10-11 16:16:02 -0400501
Neale Ranns2be95c12016-11-19 13:50:04 +0000502 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500503 {
504 ip_lookup_next_t next0, next1;
505 const load_balance_t *lb0, *lb1;
506 vlib_buffer_t *p0, *p1;
507 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
508 const ip6_header_t *ip0, *ip1;
509 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000510
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 /* Prefetch next iteration. */
512 {
513 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000514
Dave Barachd7cb1b52016-12-09 09:52:16 -0500515 p2 = vlib_get_buffer (vm, from[2]);
516 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000517
Dave Barachd7cb1b52016-12-09 09:52:16 -0500518 vlib_prefetch_buffer_header (p2, STORE);
519 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000520
Dave Barachd7cb1b52016-12-09 09:52:16 -0500521 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
522 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
523 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000524
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525 pi0 = to_next[0] = from[0];
526 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000527
Dave Barachd7cb1b52016-12-09 09:52:16 -0500528 from += 2;
529 n_left_from -= 2;
530 to_next += 2;
531 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000532
Dave Barachd7cb1b52016-12-09 09:52:16 -0500533 p0 = vlib_get_buffer (vm, pi0);
534 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000535
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 ip0 = vlib_buffer_get_current (p0);
537 ip1 = vlib_buffer_get_current (p1);
538 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
539 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000540
Dave Barachd7cb1b52016-12-09 09:52:16 -0500541 lb0 = load_balance_get (lbi0);
542 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000543
Dave Barachd7cb1b52016-12-09 09:52:16 -0500544 /*
545 * this node is for via FIBs we can re-use the hash value from the
546 * to node if present.
547 * We don't want to use the same hash value at each level in the recursion
548 * graph as that would lead to polarisation
549 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000550 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000551
Dave Barachd7cb1b52016-12-09 09:52:16 -0500552 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
553 {
554 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
555 {
556 hc0 = vnet_buffer (p0)->ip.flow_hash =
557 vnet_buffer (p0)->ip.flow_hash >> 1;
558 }
559 else
560 {
561 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000562 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500563 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700564 dpo0 =
565 load_balance_get_fwd_bucket (lb0,
566 (hc0 &
567 lb0->lb_n_buckets_minus_1));
568 }
569 else
570 {
571 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500572 }
573 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
574 {
575 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
576 {
577 hc1 = vnet_buffer (p1)->ip.flow_hash =
578 vnet_buffer (p1)->ip.flow_hash >> 1;
579 }
580 else
581 {
582 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000583 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500584 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700585 dpo1 =
586 load_balance_get_fwd_bucket (lb1,
587 (hc1 &
588 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500589 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700590 else
591 {
592 dpo1 = load_balance_get_bucket_i (lb1, 0);
593 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000594
Dave Barachd7cb1b52016-12-09 09:52:16 -0500595 next0 = dpo0->dpoi_next_node;
596 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000597
Dave Barachd7cb1b52016-12-09 09:52:16 -0500598 /* Only process the HBH Option Header if explicitly configured to do so */
599 if (PREDICT_FALSE
600 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
601 {
602 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
603 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
604 }
605 /* Only process the HBH Option Header if explicitly configured to do so */
606 if (PREDICT_FALSE
607 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
608 {
609 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
610 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
611 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000612
Dave Barachd7cb1b52016-12-09 09:52:16 -0500613 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
614 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000615
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200617 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500618 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200619 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000620
Dave Barachd7cb1b52016-12-09 09:52:16 -0500621 vlib_validate_buffer_enqueue_x2 (vm, node, next,
622 to_next, n_left_to_next,
623 pi0, pi1, next0, next1);
624 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000625
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100626 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500627 {
628 ip_lookup_next_t next0;
629 const load_balance_t *lb0;
630 vlib_buffer_t *p0;
631 u32 pi0, lbi0, hc0;
632 const ip6_header_t *ip0;
633 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100634
Dave Barachd7cb1b52016-12-09 09:52:16 -0500635 pi0 = from[0];
636 to_next[0] = pi0;
637 from += 1;
638 to_next += 1;
639 n_left_to_next -= 1;
640 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641
Dave Barachd7cb1b52016-12-09 09:52:16 -0500642 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100643
Dave Barachd7cb1b52016-12-09 09:52:16 -0500644 ip0 = vlib_buffer_get_current (p0);
645 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100646
Dave Barachd7cb1b52016-12-09 09:52:16 -0500647 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100648
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000649 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500650 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
651 {
652 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
653 {
654 hc0 = vnet_buffer (p0)->ip.flow_hash =
655 vnet_buffer (p0)->ip.flow_hash >> 1;
656 }
657 else
658 {
659 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000660 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500661 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700662 dpo0 =
663 load_balance_get_fwd_bucket (lb0,
664 (hc0 &
665 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500666 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700667 else
668 {
669 dpo0 = load_balance_get_bucket_i (lb0, 0);
670 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100671
Dave Barachd7cb1b52016-12-09 09:52:16 -0500672 next0 = dpo0->dpoi_next_node;
673 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000674
Dave Barachd7cb1b52016-12-09 09:52:16 -0500675 /* Only process the HBH Option Header if explicitly configured to do so */
676 if (PREDICT_FALSE
677 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
678 {
679 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
680 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
681 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000682
Dave Barachd7cb1b52016-12-09 09:52:16 -0500683 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200684 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100685
Dave Barachd7cb1b52016-12-09 09:52:16 -0500686 vlib_validate_buffer_enqueue_x1 (vm, node, next,
687 to_next, n_left_to_next,
688 pi0, next0);
689 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690
691 vlib_put_next_frame (vm, node, next, n_left_to_next);
692 }
693
694 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200695}
696
Dave Barachd7cb1b52016-12-09 09:52:16 -0500697/* *INDENT-OFF* */
698VLIB_REGISTER_NODE (ip6_load_balance_node) =
699{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100700 .function = ip6_load_balance,
701 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200702 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200703 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100704 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200705};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200707
Dave Barachd7cb1b52016-12-09 09:52:16 -0500708VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200709
Dave Barachd7cb1b52016-12-09 09:52:16 -0500710typedef struct
711{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700712 /* Adjacency taken. */
713 u32 adj_index;
714 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500715 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
717 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500718 u8 packet_data[128 - 1 * sizeof (u32)];
719}
720ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
John Lo2b81eb82017-01-30 13:12:10 -0500722u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500723format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100725 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
726 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500727 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200728 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100729
Dave Barachd7cb1b52016-12-09 09:52:16 -0500730 s = format (s, "%U%U",
731 format_white_space, indent,
732 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100733 return s;
734}
735
Dave Barachd7cb1b52016-12-09 09:52:16 -0500736static u8 *
737format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100738{
739 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
740 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500741 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200742 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743
John Loac8146c2016-09-27 17:44:02 -0400744 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500745 t->fib_index, t->adj_index, t->flow_hash);
746 s = format (s, "\n%U%U",
747 format_white_space, indent,
748 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100749 return s;
750}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100751
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
Dave Barachd7cb1b52016-12-09 09:52:16 -0500753static u8 *
754format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100755{
756 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
757 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500758 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200759 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100761 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500762 t->fib_index, t->adj_index, format_ip_adjacency,
763 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100764 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500765 format_white_space, indent,
766 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -0400767 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700768 return s;
769}
770
771/* Common trace function for all ip6-forward next nodes. */
772void
773ip6_forward_next_trace (vlib_main_t * vm,
774 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500775 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700776{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500777 u32 *from, n_left;
778 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700779
780 n_left = frame->n_vectors;
781 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100782
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 while (n_left >= 4)
784 {
785 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500786 vlib_buffer_t *b0, *b1;
787 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700788
789 /* Prefetch next iteration. */
790 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
791 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
792
793 bi0 = from[0];
794 bi1 = from[1];
795
796 b0 = vlib_get_buffer (vm, bi0);
797 b1 = vlib_get_buffer (vm, bi1);
798
799 if (b0->flags & VLIB_BUFFER_IS_TRACED)
800 {
801 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
802 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500803 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
804 t0->fib_index =
805 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
806 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
807 vec_elt (im->fib_index_by_sw_if_index,
808 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100809
Damjan Marionf1213b82016-03-13 02:22:06 +0100810 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500811 vlib_buffer_get_current (b0),
812 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 }
814 if (b1->flags & VLIB_BUFFER_IS_TRACED)
815 {
816 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
817 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500818 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
819 t1->fib_index =
820 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
821 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
822 vec_elt (im->fib_index_by_sw_if_index,
823 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100824
Damjan Marionf1213b82016-03-13 02:22:06 +0100825 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826 vlib_buffer_get_current (b1),
827 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 }
829 from += 2;
830 n_left -= 2;
831 }
832
833 while (n_left >= 1)
834 {
835 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500836 vlib_buffer_t *b0;
837 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838
839 bi0 = from[0];
840
841 b0 = vlib_get_buffer (vm, bi0);
842
843 if (b0->flags & VLIB_BUFFER_IS_TRACED)
844 {
845 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
846 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -0500847 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
848 t0->fib_index =
849 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
850 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
851 vec_elt (im->fib_index_by_sw_if_index,
852 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100853
Damjan Marionf1213b82016-03-13 02:22:06 +0100854 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500855 vlib_buffer_get_current (b0),
856 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857 }
858 from += 1;
859 n_left -= 1;
860 }
861}
862
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500864u16
865ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
866 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867{
868 ip_csum_t sum0;
869 u16 sum16, payload_length_host_byte_order;
870 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500871 u32 headers_size = sizeof (ip0[0]);
872 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873
Dave Barachd7cb1b52016-12-09 09:52:16 -0500874 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700875 *bogus_lengthp = 0;
876
877 /* Initialize checksum with ip header. */
878 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
879 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
880 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -0400881
Ed Warnickecb9cada2015-12-08 15:45:58 -0700882 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
883 {
884 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500885 clib_mem_unaligned (&ip0->
886 src_address.as_uword[i],
887 uword));
888 sum0 =
889 ip_csum_with_carry (sum0,
890 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
891 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700892 }
893
AkshayaNadahalli1b563522017-01-23 22:05:35 +0530894 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
895 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500896 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500898 u32 skip_bytes;
899 ip6_hop_by_hop_ext_t *ext_hdr =
900 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700901
902 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +0530903 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
904 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700905
Dave Barachd7cb1b52016-12-09 09:52:16 -0500906 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
907 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -0400908
Dave Barachd7cb1b52016-12-09 09:52:16 -0500909 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500911 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912
913 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500914 if (p0 && n_this_buffer + headers_size > p0->current_length)
915 n_this_buffer =
916 p0->current_length >
917 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918 while (1)
919 {
920 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
921 n_bytes_left -= n_this_buffer;
922 if (n_bytes_left == 0)
923 break;
924
925 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500926 {
927 *bogus_lengthp = 1;
928 return 0xfefe;
929 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700930 p0 = vlib_get_buffer (vm, p0->next_buffer);
931 data_this_buffer = vlib_buffer_get_current (p0);
932 n_this_buffer = p0->current_length;
933 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936
937 return sum16;
938}
939
Dave Barachd7cb1b52016-12-09 09:52:16 -0500940u32
941ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500943 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
944 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945 u16 sum16;
946 int bogus_length;
947
948 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
949 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
950 || ip0->protocol == IP_PROTOCOL_ICMP6
951 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -0500952 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953
954 udp0 = (void *) (ip0 + 1);
955 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
956 {
Damjan Marion213b5aa2017-07-13 21:19:27 +0200957 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
958 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959 return p0->flags;
960 }
961
962 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
963
Damjan Marion213b5aa2017-07-13 21:19:27 +0200964 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
965 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 return p0->flags;
968}
969
AkshayaNadahalli0f438df2017-02-10 10:54:16 +0530970/**
971 * @brief returns number of links on which src is reachable.
972 */
973always_inline int
974ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
975{
976 const load_balance_t *lb0;
977 index_t lbi;
Florin Corasf3a3bad2018-03-28 02:18:29 -0700978 u32 fib_index;
AkshayaNadahalli0f438df2017-02-10 10:54:16 +0530979
Florin Corasf3a3bad2018-03-28 02:18:29 -0700980 fib_index = vec_elt (im->fib_index_by_sw_if_index,
981 vnet_buffer (b)->sw_if_index[VLIB_RX]);
982 fib_index =
983 (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
984 fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
AkshayaNadahalli0f438df2017-02-10 10:54:16 +0530985
Florin Corasf3a3bad2018-03-28 02:18:29 -0700986 lbi = ip6_fib_table_fwding_lookup (im, fib_index, &i->src_address);
AkshayaNadahalli0f438df2017-02-10 10:54:16 +0530987 lb0 = load_balance_get (lbi);
988
989 return (fib_urpf_check_size (lb0->lb_urpf));
990}
991
rootc9d1c5b2017-08-15 12:58:31 -0400992always_inline u8
993ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
994 u32 * udp_offset0)
995{
996 u32 proto0;
997 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
998 if (proto0 != IP_PROTOCOL_UDP)
999 {
1000 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1001 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1002 }
1003 return proto0;
1004}
1005
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001006/* *INDENT-OFF* */
1007VNET_FEATURE_ARC_INIT (ip6_local) =
1008{
1009 .arc_name = "ip6-local",
1010 .start_nodes = VNET_FEATURES ("ip6-local"),
1011};
1012/* *INDENT-ON* */
1013
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014static uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001015ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1016 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001018 ip6_main_t *im = &ip6_main;
1019 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021 u32 *from, *to_next, n_left_from, n_left_to_next;
1022 vlib_node_runtime_t *error_node =
1023 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001024 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025
1026 from = vlib_frame_vector_args (frame);
1027 n_left_from = frame->n_vectors;
1028 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001029
Ed Warnickecb9cada2015-12-08 15:45:58 -07001030 if (node->flags & VLIB_NODE_FLAG_TRACE)
1031 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1032
1033 while (n_left_from > 0)
1034 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036
1037 while (n_left_from >= 4 && n_left_to_next >= 2)
1038 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001039 vlib_buffer_t *p0, *p1;
1040 ip6_header_t *ip0, *ip1;
1041 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042 u32 pi0, ip_len0, udp_len0, flags0, next0;
1043 u32 pi1, ip_len1, udp_len1, flags1, next1;
1044 i32 len_diff0, len_diff1;
rootc9d1c5b2017-08-15 12:58:31 -04001045 u8 error0, type0, good_l4_csum0, is_tcp_udp0;
1046 u8 error1, type1, good_l4_csum1, is_tcp_udp1;
Shwethab78292e2016-09-13 11:51:00 +01001047 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001048
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 pi0 = to_next[0] = from[0];
1050 pi1 = to_next[1] = from[1];
1051 from += 2;
1052 n_left_from -= 2;
1053 to_next += 2;
1054 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001055
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001056 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1057
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058 p0 = vlib_get_buffer (vm, pi0);
1059 p1 = vlib_get_buffer (vm, pi1);
1060
1061 ip0 = vlib_buffer_get_current (p0);
1062 ip1 = vlib_buffer_get_current (p1);
1063
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001064 if (head_of_feature_arc == 0)
1065 goto skip_checks;
1066
Damjan Marion072401e2017-07-13 18:53:27 +02001067 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1068 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001069
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1071 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1072
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073 flags0 = p0->flags;
1074 flags1 = p1->flags;
1075
rootc9d1c5b2017-08-15 12:58:31 -04001076 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1077 is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
1078
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001079 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001080 || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1081 || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001082 != 0;
1083 good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001084 || (flags1 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1085 || flags1 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001086 != 0;
Shwethab78292e2016-09-13 11:51:00 +01001087 len_diff0 = 0;
1088 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
rootc9d1c5b2017-08-15 12:58:31 -04001090 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001091 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001092 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001093 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001094 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001095 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001096 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001097 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1098 {
1099 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1100 udp_len0 = clib_net_to_host_u16 (udp0->length);
1101 len_diff0 = ip_len0 - udp_len0;
1102 }
Shwethab78292e2016-09-13 11:51:00 +01001103 }
rootc9d1c5b2017-08-15 12:58:31 -04001104 if (PREDICT_TRUE (is_tcp_udp1))
Shwethab78292e2016-09-13 11:51:00 +01001105 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001106 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001107 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001108 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001110 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001111 if (is_tcp_udp1 == IP_PROTOCOL_UDP)
1112 {
1113 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1114 udp_len1 = clib_net_to_host_u16 (udp1->length);
1115 len_diff1 = ip_len1 - udp_len1;
1116 }
Shwethab78292e2016-09-13 11:51:00 +01001117 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118
rootc9d1c5b2017-08-15 12:58:31 -04001119 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1120 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1123 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1124
1125 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001126 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001127 && !(flags0 &
1128 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129 {
1130 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001131 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001132 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001133 }
1134 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001135 && !good_l4_csum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001136 && !(flags1 &
1137 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138 {
1139 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
rootc9d1c5b2017-08-15 12:58:31 -04001140 good_l4_csum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001141 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 }
1143
1144 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1146 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1147
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1149 IP6_ERROR_UDP_CHECKSUM);
1150 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1151 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001152 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1153 error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154
1155 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001156 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001157 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1158 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001159 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301161 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001162 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001164 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1165 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001166 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301168 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001169 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170 }
1171
Florin Corascea194d2017-10-02 00:18:51 -07001172 /* TODO maybe move to lookup? */
1173 vnet_buffer (p0)->ip.fib_index =
1174 vec_elt (im->fib_index_by_sw_if_index,
1175 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1176 vnet_buffer (p0)->ip.fib_index =
1177 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1178 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1179 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1180
1181 vnet_buffer (p1)->ip.fib_index =
1182 vec_elt (im->fib_index_by_sw_if_index,
1183 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
1184 vnet_buffer (p1)->ip.fib_index =
1185 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1186 (u32) ~ 0) ? vnet_buffer (p1)->ip.
1187 fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1188
1189
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001190 skip_checks:
1191
1192 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1193 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1194
Dave Barachd7cb1b52016-12-09 09:52:16 -05001195 next0 =
1196 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1197 next1 =
1198 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199
1200 p0->error = error_node->errors[error0];
1201 p1->error = error_node->errors[error1];
1202
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001203 if (head_of_feature_arc)
1204 {
1205 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1206 vnet_feature_arc_start (arc_index,
1207 vnet_buffer (p0)->sw_if_index
1208 [VLIB_RX], &next0, p0);
1209 if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1210 vnet_feature_arc_start (arc_index,
1211 vnet_buffer (p1)->sw_if_index
1212 [VLIB_RX], &next1, p1);
1213 }
1214
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1216 to_next, n_left_to_next,
1217 pi0, pi1, next0, next1);
1218 }
1219
1220 while (n_left_from > 0 && n_left_to_next > 0)
1221 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 vlib_buffer_t *p0;
1223 ip6_header_t *ip0;
1224 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225 u32 pi0, ip_len0, udp_len0, flags0, next0;
1226 i32 len_diff0;
rootc9d1c5b2017-08-15 12:58:31 -04001227 u8 error0, type0, good_l4_csum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001228 u32 udp_offset0;
rootc9d1c5b2017-08-15 12:58:31 -04001229 u8 is_tcp_udp0;
Dave Barach75fc8542016-10-11 16:16:02 -04001230
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231 pi0 = to_next[0] = from[0];
1232 from += 1;
1233 n_left_from -= 1;
1234 to_next += 1;
1235 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001236
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001237 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1238
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240 ip0 = vlib_buffer_get_current (p0);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001241
1242 if (head_of_feature_arc == 0)
1243 goto skip_check;
1244
Damjan Marion072401e2017-07-13 18:53:27 +02001245 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001246
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001248 flags0 = p0->flags;
rootc9d1c5b2017-08-15 12:58:31 -04001249 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001250 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001251 || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1252 || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001253 != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254
Shwethab78292e2016-09-13 11:51:00 +01001255 len_diff0 = 0;
rootc9d1c5b2017-08-15 12:58:31 -04001256 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001257 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001258 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
rootc9d1c5b2017-08-15 12:58:31 -04001259 /* Don't verify UDP checksum for packets with explicit zero
1260 * checksum. */
1261 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001262 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001263 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001264 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1265 {
1266 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1267 udp_len0 = clib_net_to_host_u16 (udp0->length);
1268 len_diff0 = ip_len0 - udp_len0;
1269 }
Shwethab78292e2016-09-13 11:51:00 +01001270 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271
rootc9d1c5b2017-08-15 12:58:31 -04001272 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001273 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1274
1275 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001276 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001277 && !(flags0 &
1278 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279 {
1280 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001281 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001282 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 }
1284
1285 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1287
Dave Barachd7cb1b52016-12-09 09:52:16 -05001288 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1289 IP6_ERROR_UDP_CHECKSUM);
1290 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1291 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001292 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293
rootc9d1c5b2017-08-15 12:58:31 -04001294 /* If this is a neighbor solicitation (ICMP), skip src RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001295 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1296 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001297 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301299 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001300 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001301 }
1302
Florin Corascea194d2017-10-02 00:18:51 -07001303 vnet_buffer (p0)->ip.fib_index =
1304 vec_elt (im->fib_index_by_sw_if_index,
1305 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1306 vnet_buffer (p0)->ip.fib_index =
1307 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1308 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1309 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1310
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001311 skip_check:
1312
1313 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001314 next0 =
1315 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001316
Ed Warnickecb9cada2015-12-08 15:45:58 -07001317 p0->error = error_node->errors[error0];
1318
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001319 if (head_of_feature_arc)
1320 {
1321 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1322 vnet_feature_arc_start (arc_index,
1323 vnet_buffer (p0)->sw_if_index
1324 [VLIB_RX], &next0, p0);
1325 }
1326
Ed Warnickecb9cada2015-12-08 15:45:58 -07001327 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1328 to_next, n_left_to_next,
1329 pi0, next0);
1330 }
Dave Barach75fc8542016-10-11 16:16:02 -04001331
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1333 }
1334
1335 return frame->n_vectors;
1336}
1337
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001338static uword
1339ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1340{
1341 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1342}
1343
Dave Barachd7cb1b52016-12-09 09:52:16 -05001344/* *INDENT-OFF* */
1345VLIB_REGISTER_NODE (ip6_local_node, static) =
1346{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347 .function = ip6_local,
1348 .name = "ip6-local",
1349 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001352 .next_nodes =
1353 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001354 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1355 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1357 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1358 },
1359};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001360/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001361
Dave Barachd7cb1b52016-12-09 09:52:16 -05001362VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001363
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001364
1365static uword
1366ip6_local_end_of_arc (vlib_main_t * vm,
1367 vlib_node_runtime_t * node, vlib_frame_t * frame)
1368{
1369 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1370}
1371
1372/* *INDENT-OFF* */
1373VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
1374 .function = ip6_local_end_of_arc,
1375 .name = "ip6-local-end-of-arc",
1376 .vector_size = sizeof (u32),
1377
1378 .format_trace = format_ip6_forward_next_trace,
1379 .sibling_of = "ip6-local",
1380};
1381
1382VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
1383
1384VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1385 .arc_name = "ip6-local",
1386 .node_name = "ip6-local-end-of-arc",
1387 .runs_before = 0, /* not before any other features */
1388};
1389/* *INDENT-ON* */
1390
Dave Barachd7cb1b52016-12-09 09:52:16 -05001391void
1392ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001394 vlib_main_t *vm = vlib_get_main ();
1395 ip6_main_t *im = &ip6_main;
1396 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397
1398 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001399 lm->local_next_by_ip_protocol[protocol] =
1400 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401}
1402
Dave Barachd7cb1b52016-12-09 09:52:16 -05001403typedef enum
1404{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001406 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1408} ip6_discover_neighbor_next_t;
1409
Dave Barachd7cb1b52016-12-09 09:52:16 -05001410typedef enum
1411{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001412 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1413 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001414 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001415} ip6_discover_neighbor_error_t;
1416
1417static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001418ip6_discover_neighbor_inline (vlib_main_t * vm,
1419 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001420 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001422 vnet_main_t *vnm = vnet_get_main ();
1423 ip6_main_t *im = &ip6_main;
1424 ip_lookup_main_t *lm = &im->lookup_main;
1425 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 uword n_left_from, n_left_to_next_drop;
1427 static f64 time_last_seed_change = -1e100;
1428 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001429 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430 f64 time_now;
1431 int bogus_length;
1432
1433 if (node->flags & VLIB_NODE_FLAG_TRACE)
1434 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1435
1436 time_now = vlib_time_now (vm);
1437 if (time_now - time_last_seed_change > 1e-3)
1438 {
1439 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001440 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1441 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001442 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1443 hash_seeds[i] = r[i];
1444
1445 /* Mark all hash keys as been not-seen before. */
1446 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1447 hash_bitmap[i] = 0;
1448
1449 time_last_seed_change = time_now;
1450 }
1451
1452 from = vlib_frame_vector_args (frame);
1453 n_left_from = frame->n_vectors;
1454
1455 while (n_left_from > 0)
1456 {
1457 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1458 to_next_drop, n_left_to_next_drop);
1459
1460 while (n_left_from > 0 && n_left_to_next_drop > 0)
1461 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001462 vlib_buffer_t *p0;
1463 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001464 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1465 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001466 ip_adjacency_t *adj0;
1467 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001468 u32 next0;
1469
1470 pi0 = from[0];
1471
1472 p0 = vlib_get_buffer (vm, pi0);
1473
1474 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1475
1476 ip0 = vlib_buffer_get_current (p0);
1477
Neale Ranns107e7d42017-04-11 09:55:19 -07001478 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001479
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001480 if (!is_glean)
1481 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001482 ip0->dst_address.as_u64[0] =
1483 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1484 ip0->dst_address.as_u64[1] =
1485 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001486 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001487
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488 a0 = hash_seeds[0];
1489 b0 = hash_seeds[1];
1490 c0 = hash_seeds[2];
1491
1492 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1493 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1494
1495 a0 ^= sw_if_index0;
1496 b0 ^= ip0->dst_address.as_u32[0];
1497 c0 ^= ip0->dst_address.as_u32[1];
1498
1499 hash_v3_mix32 (a0, b0, c0);
1500
1501 b0 ^= ip0->dst_address.as_u32[2];
1502 c0 ^= ip0->dst_address.as_u32[3];
1503
1504 hash_v3_finalize32 (a0, b0, c0);
1505
1506 c0 &= BITS (hash_bitmap) - 1;
1507 c0 = c0 / BITS (uword);
1508 m0 = (uword) 1 << (c0 % BITS (uword));
1509
1510 bm0 = hash_bitmap[c0];
1511 drop0 = (bm0 & m0) != 0;
1512
1513 /* Mark it as seen. */
1514 hash_bitmap[c0] = bm0 | m0;
1515
1516 from += 1;
1517 n_left_from -= 1;
1518 to_next_drop[0] = pi0;
1519 to_next_drop += 1;
1520 n_left_to_next_drop -= 1;
1521
Dave Barachd7cb1b52016-12-09 09:52:16 -05001522 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001523
Dave Barachd7cb1b52016-12-09 09:52:16 -05001524 /* If the interface is link-down, drop the pkt */
1525 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1526 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527
Dave Barach75fc8542016-10-11 16:16:02 -04001528 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1530 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001531 if (drop0)
1532 continue;
1533
Neale Rannsb80c5362016-10-08 13:03:40 +01001534 /*
1535 * the adj has been updated to a rewrite but the node the DPO that got
1536 * us here hasn't - yet. no big deal. we'll drop while we wait.
1537 */
1538 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1539 continue;
1540
Ed Warnickecb9cada2015-12-08 15:45:58 -07001541 {
1542 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001543 icmp6_neighbor_solicitation_header_t *h0;
1544 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001545
Dave Barach75fc8542016-10-11 16:16:02 -04001546 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001547 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548
Dave Barach75fc8542016-10-11 16:16:02 -04001549 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001550 * Build ethernet header.
1551 * Choose source address based on destination lookup
1552 * adjacency.
1553 */
Neale Ranns53da2212018-02-24 02:11:19 -08001554 if (!ip6_src_address_for_packet (lm,
1555 sw_if_index0,
1556 &ip0->dst_address,
1557 &h0->ip.src_address))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001558 {
1559 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001560 p0->error =
1561 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1562 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001563 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001564 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001565
Dave Barach75fc8542016-10-11 16:16:02 -04001566 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001567 * Destination address is a solicited node multicast address.
1568 * We need to fill in
1569 * the low 24 bits with low 24 bits of target's address.
1570 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1572 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1573 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1574
1575 h0->neighbor.target_address = ip0->dst_address;
1576
Dave Barach75fc8542016-10-11 16:16:02 -04001577 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001578 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001579
Dave Barachd7cb1b52016-12-09 09:52:16 -05001580 /* $$$$ appears we need this; why is the checksum non-zero? */
1581 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001582 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001583 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1584 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585
Dave Barachd7cb1b52016-12-09 09:52:16 -05001586 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001587
1588 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1589 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001590 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001591 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001592
1593 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001594 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001595 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1596
John Lod1f5d042016-04-12 18:20:39 -04001597 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598
1599 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1600 }
1601 }
1602
Dave Barach75fc8542016-10-11 16:16:02 -04001603 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001604 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 }
1606
1607 return frame->n_vectors;
1608}
1609
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001610static uword
1611ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001612 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001613{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001614 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001615}
1616
1617static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001618ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001619{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001620 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001621}
1622
Dave Barachd7cb1b52016-12-09 09:52:16 -05001623static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001624 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001625 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001626 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1627 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001628};
1629
Dave Barachd7cb1b52016-12-09 09:52:16 -05001630/* *INDENT-OFF* */
1631VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1632{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001633 .function = ip6_discover_neighbor,
1634 .name = "ip6-discover-neighbor",
1635 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001636 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001637 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1638 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001639 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001640 .next_nodes =
1641 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08001642 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
John Lod1f5d042016-04-12 18:20:39 -04001643 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 },
1645};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001646/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001647
Dave Barachd7cb1b52016-12-09 09:52:16 -05001648/* *INDENT-OFF* */
1649VLIB_REGISTER_NODE (ip6_glean_node) =
1650{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001651 .function = ip6_glean,
1652 .name = "ip6-glean",
1653 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001654 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001655 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1656 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001657 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001658 .next_nodes =
1659 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08001660 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001661 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1662 },
1663};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001664/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001665
Ed Warnickecb9cada2015-12-08 15:45:58 -07001666clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1668{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001669 vnet_main_t *vnm = vnet_get_main ();
1670 ip6_main_t *im = &ip6_main;
1671 icmp6_neighbor_solicitation_header_t *h;
1672 ip6_address_t *src;
1673 ip_interface_address_t *ia;
1674 ip_adjacency_t *adj;
1675 vnet_hw_interface_t *hi;
1676 vnet_sw_interface_t *si;
1677 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001678 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001679 u32 bi = 0;
1680 int bogus_length;
1681
1682 si = vnet_get_sw_interface (vnm, sw_if_index);
1683
1684 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1685 {
1686 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001687 format_ip6_address, dst,
1688 format_vnet_sw_if_index_name, vnm,
1689 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001690 }
1691
Dave Barachd7cb1b52016-12-09 09:52:16 -05001692 src =
1693 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1694 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001695 {
1696 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001697 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001698 (0, "no matching interface address for destination %U (interface %U)",
1699 format_ip6_address, dst,
1700 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001701 }
1702
Dave Barachd7cb1b52016-12-09 09:52:16 -05001703 h =
1704 vlib_packet_template_get_packet (vm,
1705 &im->discover_neighbor_packet_template,
1706 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001707
1708 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1709
1710 /* Destination address is a solicited node multicast address. We need to fill in
1711 the low 24 bits with low 24 bits of target's address. */
1712 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1713 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1714 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1715
1716 h->ip.src_address = src[0];
1717 h->neighbor.target_address = dst[0];
1718
Pavel Kotucek57808982017-08-02 08:20:19 +02001719 if (PREDICT_FALSE (!hi->hw_address))
1720 {
1721 return clib_error_return (0, "%U: interface %U do not support ip probe",
1722 format_ip6_address, dst,
1723 format_vnet_sw_if_index_name, vnm,
1724 sw_if_index);
1725 }
1726
Dave Barachd7cb1b52016-12-09 09:52:16 -05001727 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1728 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001729
Dave Barach75fc8542016-10-11 16:16:02 -04001730 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001731 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733
1734 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001735 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1736 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001737
1738 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07001739 ip46_address_t nh = {
1740 .ip6 = *dst,
1741 };
1742
1743 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
1744 VNET_LINK_IP6, &nh, sw_if_index);
1745 adj = adj_get (ai);
1746
Dave Barach59b25652017-09-10 15:04:27 -04001747 /* Peer has been previously resolved, retrieve glean adj instead */
1748 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1749 {
1750 adj_unlock (ai);
Ole Troan6ee40512018-02-12 18:14:39 +01001751 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6,
1752 VNET_LINK_IP6, sw_if_index, &nh);
Dave Barach59b25652017-09-10 15:04:27 -04001753 adj = adj_get (ai);
1754 }
1755
Ed Warnickecb9cada2015-12-08 15:45:58 -07001756 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1757 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1758
1759 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1761 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762 to_next[0] = bi;
1763 f->n_vectors = 1;
1764 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1765 }
1766
Neale Ranns7a272742017-05-30 02:08:14 -07001767 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 return /* no error */ 0;
1769}
1770
Dave Barachd7cb1b52016-12-09 09:52:16 -05001771typedef enum
1772{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001774 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001775} ip6_rewrite_next_t;
1776
1777always_inline uword
1778ip6_rewrite_inline (vlib_main_t * vm,
1779 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001780 vlib_frame_t * frame,
1781 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001783 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1784 u32 *from = vlib_frame_vector_args (frame);
1785 u32 n_left_from, n_left_to_next, *to_next, next_index;
1786 vlib_node_runtime_t *error_node =
1787 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788
1789 n_left_from = frame->n_vectors;
1790 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02001791 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04001792
Ed Warnickecb9cada2015-12-08 15:45:58 -07001793 while (n_left_from > 0)
1794 {
1795 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1796
1797 while (n_left_from >= 4 && n_left_to_next >= 2)
1798 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 ip_adjacency_t *adj0, *adj1;
1800 vlib_buffer_t *p0, *p1;
1801 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001802 u32 pi0, rw_len0, next0, error0, adj_index0;
1803 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001804 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001805
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806 /* Prefetch next iteration. */
1807 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001808 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809
1810 p2 = vlib_get_buffer (vm, from[2]);
1811 p3 = vlib_get_buffer (vm, from[3]);
1812
1813 vlib_prefetch_buffer_header (p2, LOAD);
1814 vlib_prefetch_buffer_header (p3, LOAD);
1815
1816 CLIB_PREFETCH (p2->pre_data, 32, STORE);
1817 CLIB_PREFETCH (p3->pre_data, 32, STORE);
1818
1819 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1820 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1821 }
1822
1823 pi0 = to_next[0] = from[0];
1824 pi1 = to_next[1] = from[1];
1825
1826 from += 2;
1827 n_left_from -= 2;
1828 to_next += 2;
1829 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001830
Ed Warnickecb9cada2015-12-08 15:45:58 -07001831 p0 = vlib_get_buffer (vm, pi0);
1832 p1 = vlib_get_buffer (vm, pi1);
1833
Neale Rannsf06aea52016-11-29 06:51:37 -08001834 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1835 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001836
Ed Warnickecb9cada2015-12-08 15:45:58 -07001837 ip0 = vlib_buffer_get_current (p0);
1838 ip1 = vlib_buffer_get_current (p1);
1839
1840 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842
Damjan Marion213b5aa2017-07-13 21:19:27 +02001843 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001844 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001845 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846
1847 /* Input node should have reject packets with hop limit 0. */
1848 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849
1850 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851
1852 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001853
Dave Barachd7cb1b52016-12-09 09:52:16 -05001854 /*
1855 * If the hop count drops below 1 when forwarding, generate
1856 * an ICMP response.
1857 */
1858 if (PREDICT_FALSE (hop_limit0 <= 0))
1859 {
1860 error0 = IP6_ERROR_TIME_EXPIRED;
1861 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1862 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1863 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1864 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1865 0);
1866 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001867 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001868 else
1869 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001870 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001871 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02001872 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001873 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001874 i32 hop_limit1 = ip1->hop_limit;
1875
1876 /* Input node should have reject packets with hop limit 0. */
1877 ASSERT (ip1->hop_limit > 0);
1878
1879 hop_limit1 -= 1;
1880
1881 ip1->hop_limit = hop_limit1;
1882
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883 /*
1884 * If the hop count drops below 1 when forwarding, generate
1885 * an ICMP response.
1886 */
1887 if (PREDICT_FALSE (hop_limit1 <= 0))
1888 {
1889 error1 = IP6_ERROR_TIME_EXPIRED;
1890 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1891 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1892 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1893 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1894 0);
1895 }
1896 }
1897 else
1898 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001899 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900 }
Neale Ranns107e7d42017-04-11 09:55:19 -07001901 adj0 = adj_get (adj_index0);
1902 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904 rw_len0 = adj0[0].rewrite_header.data_bytes;
1905 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001906 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1907 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001908
Neale Ranns9c6a6132017-02-21 05:33:14 -08001909 if (do_counters)
1910 {
1911 vlib_increment_combined_counter
1912 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001913 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001914 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1915 vlib_increment_combined_counter
1916 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02001917 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001918 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1919 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920
1921 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 error0 =
1923 (vlib_buffer_length_in_chain (vm, p0) >
1924 adj0[0].
1925 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
1926 error0);
1927 error1 =
1928 (vlib_buffer_length_in_chain (vm, p1) >
1929 adj1[0].
1930 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
1931 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932
Dave Barachd7cb1b52016-12-09 09:52:16 -05001933 /* Don't adjust the buffer for hop count issue; icmp-error node
1934 * wants to see the IP headerr */
1935 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1936 {
1937 p0->current_data -= rw_len0;
1938 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001939
Dave Barachd7cb1b52016-12-09 09:52:16 -05001940 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1941 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1942 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001943
Neale Rannsb069a692017-03-15 12:34:25 -04001944 if (PREDICT_FALSE
1945 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1946 vnet_feature_arc_start (lm->output_feature_arc_index,
1947 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001948 }
1949 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1950 {
1951 p1->current_data -= rw_len1;
1952 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953
Dave Barachd7cb1b52016-12-09 09:52:16 -05001954 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1955 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1956 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04001957
Neale Rannsb069a692017-03-15 12:34:25 -04001958 if (PREDICT_FALSE
1959 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1960 vnet_feature_arc_start (lm->output_feature_arc_index,
1961 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001962 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963
1964 /* Guess we are only writing on simple Ethernet header. */
1965 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05001966 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04001967
Neale Ranns5e575b12016-10-03 09:40:25 +01001968 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001969 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08001970 adj0->sub_type.midchain.fixup_func
1971 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1972 adj1->sub_type.midchain.fixup_func
1973 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001974 }
Neale Ranns32e1c012016-11-22 17:07:28 +00001975 if (is_mcast)
1976 {
1977 /*
1978 * copy bytes from the IP address into the MAC rewrite
1979 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07001980 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
1981 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00001982 }
Neale Ranns5e575b12016-10-03 09:40:25 +01001983
Ed Warnickecb9cada2015-12-08 15:45:58 -07001984 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1985 to_next, n_left_to_next,
1986 pi0, pi1, next0, next1);
1987 }
1988
1989 while (n_left_from > 0 && n_left_to_next > 0)
1990 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001991 ip_adjacency_t *adj0;
1992 vlib_buffer_t *p0;
1993 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994 u32 pi0, rw_len0;
1995 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001996 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04001997
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998 pi0 = to_next[0] = from[0];
1999
2000 p0 = vlib_get_buffer (vm, pi0);
2001
Neale Rannsf06aea52016-11-29 06:51:37 -08002002 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003
Neale Ranns107e7d42017-04-11 09:55:19 -07002004 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002005
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006 ip0 = vlib_buffer_get_current (p0);
2007
2008 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002009 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002010
2011 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002012 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013 {
2014 i32 hop_limit0 = ip0->hop_limit;
2015
2016 ASSERT (ip0->hop_limit > 0);
2017
2018 hop_limit0 -= 1;
2019
2020 ip0->hop_limit = hop_limit0;
2021
Dave Barachd7cb1b52016-12-09 09:52:16 -05002022 if (PREDICT_FALSE (hop_limit0 <= 0))
2023 {
2024 /*
2025 * If the hop count drops below 1 when forwarding, generate
2026 * an ICMP response.
2027 */
2028 error0 = IP6_ERROR_TIME_EXPIRED;
2029 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2030 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2031 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2032 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2033 0);
2034 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002035 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 else
2037 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002038 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002039 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041 /* Guess we are only writing on simple Ethernet header. */
2042 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002043
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044 /* Update packet buffer attributes/set output interface. */
2045 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002046 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047
Neale Ranns9c6a6132017-02-21 05:33:14 -08002048 if (do_counters)
2049 {
2050 vlib_increment_combined_counter
2051 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002052 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002053 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2054 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055
2056 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002057 error0 =
2058 (vlib_buffer_length_in_chain (vm, p0) >
2059 adj0[0].
2060 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2061 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062
Dave Barachd7cb1b52016-12-09 09:52:16 -05002063 /* Don't adjust the buffer for hop count issue; icmp-error node
2064 * wants to see the IP headerr */
2065 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2066 {
Chris Luke816f3e12016-06-14 16:24:47 -04002067 p0->current_data -= rw_len0;
2068 p0->current_length += rw_len0;
2069
Dave Barachd7cb1b52016-12-09 09:52:16 -05002070 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002071
Dave Barachd7cb1b52016-12-09 09:52:16 -05002072 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2073 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002074
Neale Rannsb069a692017-03-15 12:34:25 -04002075 if (PREDICT_FALSE
2076 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2077 vnet_feature_arc_start (lm->output_feature_arc_index,
2078 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002079 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002080
Neale Ranns5e575b12016-10-03 09:40:25 +01002081 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002082 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08002083 adj0->sub_type.midchain.fixup_func
2084 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002085 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002086 if (is_mcast)
2087 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002088 vnet_fixup_one_header (adj0[0], &ip0->dst_address, 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 p0->error = error_node->errors[error0];
2092
2093 from += 1;
2094 n_left_from -= 1;
2095 to_next += 1;
2096 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002097
Ed Warnickecb9cada2015-12-08 15:45:58 -07002098 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2099 to_next, n_left_to_next,
2100 pi0, next0);
2101 }
2102
2103 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2104 }
2105
2106 /* Need to do trace after rewrites to pick up new packet data. */
2107 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002108 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109
2110 return frame->n_vectors;
2111}
2112
2113static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002114ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002115 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002117 if (adj_are_counters_enabled ())
2118 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2119 else
2120 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002121}
2122
2123static uword
2124ip6_rewrite_mcast (vlib_main_t * vm,
2125 vlib_node_runtime_t * node, vlib_frame_t * frame)
2126{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002127 if (adj_are_counters_enabled ())
2128 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2129 else
2130 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002131}
2132
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002133static uword
2134ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002135 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002136{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002137 if (adj_are_counters_enabled ())
2138 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2139 else
2140 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002141}
2142
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002143static uword
2144ip6_mcast_midchain (vlib_main_t * vm,
2145 vlib_node_runtime_t * node, vlib_frame_t * frame)
2146{
2147 if (adj_are_counters_enabled ())
2148 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2149 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002150 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002151}
2152
Dave Barachd7cb1b52016-12-09 09:52:16 -05002153/* *INDENT-OFF* */
2154VLIB_REGISTER_NODE (ip6_midchain_node) =
2155{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002156 .function = ip6_midchain,
2157 .name = "ip6-midchain",
2158 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002159 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002160 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002161 };
2162/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002163
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002165
Dave Barachd7cb1b52016-12-09 09:52:16 -05002166/* *INDENT-OFF* */
2167VLIB_REGISTER_NODE (ip6_rewrite_node) =
2168{
Neale Rannsf06aea52016-11-29 06:51:37 -08002169 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 .name = "ip6-rewrite",
2171 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002172 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002173 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002174 .next_nodes =
2175 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002176 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002177 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002178 },
2179};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002180/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002181
Neale Rannsf06aea52016-11-29 06:51:37 -08002182VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002183
Neale Ranns32e1c012016-11-22 17:07:28 +00002184/* *INDENT-OFF* */
2185VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2186{
2187 .function = ip6_rewrite_mcast,
2188 .name = "ip6-rewrite-mcast",
2189 .vector_size = sizeof (u32),
2190 .format_trace = format_ip6_rewrite_trace,
2191 .sibling_of = "ip6-rewrite",
2192};
2193/* *INDENT-ON* */
2194
2195VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2196
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002197/* *INDENT-OFF* */
2198VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2199{
2200 .function = ip6_mcast_midchain,
2201 .name = "ip6-mcast-midchain",
2202 .vector_size = sizeof (u32),
2203 .format_trace = format_ip6_rewrite_trace,
2204 .sibling_of = "ip6-rewrite",
2205};
2206/* *INDENT-ON* */
2207
2208VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2209
Ole Troan944f5482016-05-24 11:56:58 +02002210/*
2211 * Hop-by-Hop handling
2212 */
Ole Troan944f5482016-05-24 11:56:58 +02002213ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2214
2215#define foreach_ip6_hop_by_hop_error \
2216_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2217_(FORMAT, "incorrectly formatted hop-by-hop options") \
2218_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2219
Neale Ranns32e1c012016-11-22 17:07:28 +00002220/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002221typedef enum
2222{
Ole Troan944f5482016-05-24 11:56:58 +02002223#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2224 foreach_ip6_hop_by_hop_error
2225#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002226 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002227} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002228/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002229
2230/*
2231 * Primary h-b-h handler trace support
2232 * We work pretty hard on the problem for obvious reasons
2233 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002234typedef struct
2235{
Ole Troan944f5482016-05-24 11:56:58 +02002236 u32 next_index;
2237 u32 trace_len;
2238 u8 option_data[256];
2239} ip6_hop_by_hop_trace_t;
2240
2241vlib_node_registration_t ip6_hop_by_hop_node;
2242
Dave Barachd7cb1b52016-12-09 09:52:16 -05002243static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002244#define _(sym,string) string,
2245 foreach_ip6_hop_by_hop_error
2246#undef _
2247};
2248
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302249u8 *
2250format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2251{
2252 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2253 int total_len = va_arg (*args, int);
2254 ip6_hop_by_hop_option_t *opt0, *limit0;
2255 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2256 u8 type0;
2257
2258 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2259 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2260
2261 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2262 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2263
2264 while (opt0 < limit0)
2265 {
2266 type0 = opt0->type;
2267 switch (type0)
2268 {
2269 case 0: /* Pad, just stop */
2270 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2271 break;
2272
2273 default:
2274 if (hm->trace[type0])
2275 {
2276 s = (*hm->trace[type0]) (s, opt0);
2277 }
2278 else
2279 {
2280 s =
2281 format (s, "\n unrecognized option %d length %d", type0,
2282 opt0->length);
2283 }
2284 opt0 =
2285 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2286 sizeof (ip6_hop_by_hop_option_t));
2287 break;
2288 }
2289 }
2290 return s;
2291}
2292
Ole Troan944f5482016-05-24 11:56:58 +02002293static u8 *
2294format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2295{
2296 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2297 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002298 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002299 ip6_hop_by_hop_header_t *hbh0;
2300 ip6_hop_by_hop_option_t *opt0, *limit0;
2301 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2302
2303 u8 type0;
2304
Dave Barachd7cb1b52016-12-09 09:52:16 -05002305 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002306
2307 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002308 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002309
Dave Barachd7cb1b52016-12-09 09:52:16 -05002310 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2311 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002312
Dave Barachd7cb1b52016-12-09 09:52:16 -05002313 while (opt0 < limit0)
2314 {
2315 type0 = opt0->type;
2316 switch (type0)
2317 {
2318 case 0: /* Pad, just stop */
2319 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2320 break;
Ole Troan944f5482016-05-24 11:56:58 +02002321
Dave Barachd7cb1b52016-12-09 09:52:16 -05002322 default:
2323 if (hm->trace[type0])
2324 {
2325 s = (*hm->trace[type0]) (s, opt0);
2326 }
2327 else
2328 {
2329 s =
2330 format (s, "\n unrecognized option %d length %d", type0,
2331 opt0->length);
2332 }
2333 opt0 =
2334 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2335 sizeof (ip6_hop_by_hop_option_t));
2336 break;
2337 }
Ole Troan944f5482016-05-24 11:56:58 +02002338 }
Ole Troan944f5482016-05-24 11:56:58 +02002339 return s;
2340}
2341
Dave Barachd7cb1b52016-12-09 09:52:16 -05002342always_inline u8
2343ip6_scan_hbh_options (vlib_buffer_t * b0,
2344 ip6_header_t * ip0,
2345 ip6_hop_by_hop_header_t * hbh0,
2346 ip6_hop_by_hop_option_t * opt0,
2347 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002348{
2349 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2350 u8 type0;
2351 u8 error0 = 0;
2352
2353 while (opt0 < limit0)
2354 {
2355 type0 = opt0->type;
2356 switch (type0)
2357 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002358 case 0: /* Pad1 */
2359 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002360 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002361 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002362 break;
2363 default:
2364 if (hm->options[type0])
2365 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002366 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2367 {
Shwethaa91cbe62016-08-08 15:51:04 +01002368 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002369 return (error0);
2370 }
Shwethaa91cbe62016-08-08 15:51:04 +01002371 }
2372 else
2373 {
2374 /* Unrecognized mandatory option, check the two high order bits */
2375 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2376 {
2377 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2378 break;
2379 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2380 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2381 *next0 = IP_LOOKUP_NEXT_DROP;
2382 break;
2383 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2384 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2385 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002386 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2387 ICMP6_parameter_problem_unrecognized_option,
2388 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002389 break;
2390 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2391 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002392 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002393 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2395 icmp6_error_set_vnet_buffer (b0,
2396 ICMP6_parameter_problem,
2397 ICMP6_parameter_problem_unrecognized_option,
2398 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002399 }
2400 else
2401 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002402 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002403 }
2404 break;
2405 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002406 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002407 }
2408 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002409 opt0 =
2410 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2411 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002412 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002413 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002414}
2415
Ole Troan944f5482016-05-24 11:56:58 +02002416/*
2417 * Process the Hop-by-Hop Options header
2418 */
2419static uword
2420ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002421 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002422{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002423 vlib_node_runtime_t *error_node =
2424 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002425 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2426 u32 n_left_from, *from, *to_next;
2427 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002428
2429 from = vlib_frame_vector_args (frame);
2430 n_left_from = frame->n_vectors;
2431 next_index = node->cached_next_index;
2432
Dave Barachd7cb1b52016-12-09 09:52:16 -05002433 while (n_left_from > 0)
2434 {
2435 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002436
Dave Barachd7cb1b52016-12-09 09:52:16 -05002437 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002438
Dave Barachd7cb1b52016-12-09 09:52:16 -05002439 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002440 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002441 u32 bi0, bi1;
2442 vlib_buffer_t *b0, *b1;
2443 u32 next0, next1;
2444 ip6_header_t *ip0, *ip1;
2445 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2446 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2447 u8 error0 = 0, error1 = 0;
2448
2449 /* Prefetch next iteration. */
2450 {
2451 vlib_buffer_t *p2, *p3;
2452
2453 p2 = vlib_get_buffer (vm, from[2]);
2454 p3 = vlib_get_buffer (vm, from[3]);
2455
2456 vlib_prefetch_buffer_header (p2, LOAD);
2457 vlib_prefetch_buffer_header (p3, LOAD);
2458
2459 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2460 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002461 }
2462
Dave Barachd7cb1b52016-12-09 09:52:16 -05002463 /* Speculatively enqueue b0, b1 to the current next frame */
2464 to_next[0] = bi0 = from[0];
2465 to_next[1] = bi1 = from[1];
2466 from += 2;
2467 to_next += 2;
2468 n_left_from -= 2;
2469 n_left_to_next -= 2;
2470
2471 b0 = vlib_get_buffer (vm, bi0);
2472 b1 = vlib_get_buffer (vm, bi1);
2473
2474 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2475 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002476 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002477 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002478 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002479
2480 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2481 next0 = adj0->lookup_next_index;
2482 next1 = adj1->lookup_next_index;
2483
2484 ip0 = vlib_buffer_get_current (b0);
2485 ip1 = vlib_buffer_get_current (b1);
2486 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2487 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2488 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2489 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2490 limit0 =
2491 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2492 ((hbh0->length + 1) << 3));
2493 limit1 =
2494 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2495 ((hbh1->length + 1) << 3));
2496
2497 /*
2498 * Basic validity checks
2499 */
2500 if ((hbh0->length + 1) << 3 >
2501 clib_net_to_host_u16 (ip0->payload_length))
2502 {
2503 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2504 next0 = IP_LOOKUP_NEXT_DROP;
2505 goto outdual;
2506 }
2507 /* Scan the set of h-b-h options, process ones that we understand */
2508 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2509
2510 if ((hbh1->length + 1) << 3 >
2511 clib_net_to_host_u16 (ip1->payload_length))
2512 {
2513 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2514 next1 = IP_LOOKUP_NEXT_DROP;
2515 goto outdual;
2516 }
2517 /* Scan the set of h-b-h options, process ones that we understand */
2518 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2519
2520 outdual:
2521 /* Has the classifier flagged this buffer for special treatment? */
2522 if (PREDICT_FALSE
2523 ((error0 == 0)
2524 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2525 next0 = hm->next_override;
2526
2527 /* Has the classifier flagged this buffer for special treatment? */
2528 if (PREDICT_FALSE
2529 ((error1 == 0)
2530 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2531 next1 = hm->next_override;
2532
2533 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2534 {
2535 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2536 {
2537 ip6_hop_by_hop_trace_t *t =
2538 vlib_add_trace (vm, node, b0, sizeof (*t));
2539 u32 trace_len = (hbh0->length + 1) << 3;
2540 t->next_index = next0;
2541 /* Capture the h-b-h option verbatim */
2542 trace_len =
2543 trace_len <
2544 ARRAY_LEN (t->option_data) ? trace_len :
2545 ARRAY_LEN (t->option_data);
2546 t->trace_len = trace_len;
2547 clib_memcpy (t->option_data, hbh0, trace_len);
2548 }
2549 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2550 {
2551 ip6_hop_by_hop_trace_t *t =
2552 vlib_add_trace (vm, node, b1, sizeof (*t));
2553 u32 trace_len = (hbh1->length + 1) << 3;
2554 t->next_index = next1;
2555 /* Capture the h-b-h option verbatim */
2556 trace_len =
2557 trace_len <
2558 ARRAY_LEN (t->option_data) ? trace_len :
2559 ARRAY_LEN (t->option_data);
2560 t->trace_len = trace_len;
2561 clib_memcpy (t->option_data, hbh1, trace_len);
2562 }
2563
2564 }
2565
2566 b0->error = error_node->errors[error0];
2567 b1->error = error_node->errors[error1];
2568
2569 /* verify speculative enqueue, maybe switch current next frame */
2570 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2571 n_left_to_next, bi0, bi1, next0,
2572 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002573 }
2574
Dave Barachd7cb1b52016-12-09 09:52:16 -05002575 while (n_left_from > 0 && n_left_to_next > 0)
2576 {
2577 u32 bi0;
2578 vlib_buffer_t *b0;
2579 u32 next0;
2580 ip6_header_t *ip0;
2581 ip6_hop_by_hop_header_t *hbh0;
2582 ip6_hop_by_hop_option_t *opt0, *limit0;
2583 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002584
Dave Barachd7cb1b52016-12-09 09:52:16 -05002585 /* Speculatively enqueue b0 to the current next frame */
2586 bi0 = from[0];
2587 to_next[0] = bi0;
2588 from += 1;
2589 to_next += 1;
2590 n_left_from -= 1;
2591 n_left_to_next -= 1;
2592
2593 b0 = vlib_get_buffer (vm, bi0);
2594 /*
2595 * Default use the next_index from the adjacency.
2596 * A HBH option rarely redirects to a different node
2597 */
2598 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002599 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002600 next0 = adj0->lookup_next_index;
2601
2602 ip0 = vlib_buffer_get_current (b0);
2603 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2604 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2605 limit0 =
2606 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2607 ((hbh0->length + 1) << 3));
2608
2609 /*
2610 * Basic validity checks
2611 */
2612 if ((hbh0->length + 1) << 3 >
2613 clib_net_to_host_u16 (ip0->payload_length))
2614 {
2615 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2616 next0 = IP_LOOKUP_NEXT_DROP;
2617 goto out0;
2618 }
2619
2620 /* Scan the set of h-b-h options, process ones that we understand */
2621 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2622
2623 out0:
2624 /* Has the classifier flagged this buffer for special treatment? */
2625 if (PREDICT_FALSE
2626 ((error0 == 0)
2627 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2628 next0 = hm->next_override;
2629
2630 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2631 {
2632 ip6_hop_by_hop_trace_t *t =
2633 vlib_add_trace (vm, node, b0, sizeof (*t));
2634 u32 trace_len = (hbh0->length + 1) << 3;
2635 t->next_index = next0;
2636 /* Capture the h-b-h option verbatim */
2637 trace_len =
2638 trace_len <
2639 ARRAY_LEN (t->option_data) ? trace_len :
2640 ARRAY_LEN (t->option_data);
2641 t->trace_len = trace_len;
2642 clib_memcpy (t->option_data, hbh0, trace_len);
2643 }
2644
2645 b0->error = error_node->errors[error0];
2646
2647 /* verify speculative enqueue, maybe switch current next frame */
2648 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2649 n_left_to_next, bi0, next0);
2650 }
2651 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002652 }
Ole Troan944f5482016-05-24 11:56:58 +02002653 return frame->n_vectors;
2654}
2655
Dave Barachd7cb1b52016-12-09 09:52:16 -05002656/* *INDENT-OFF* */
2657VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2658{
Ole Troan944f5482016-05-24 11:56:58 +02002659 .function = ip6_hop_by_hop,
2660 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002661 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002662 .vector_size = sizeof (u32),
2663 .format_trace = format_ip6_hop_by_hop_trace,
2664 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002665 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002666 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002667 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002668};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002669/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002670
Dave Barach5331c722016-08-17 11:54:30 -04002671VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002672
2673static clib_error_t *
2674ip6_hop_by_hop_init (vlib_main_t * vm)
2675{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002676 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2677 memset (hm->options, 0, sizeof (hm->options));
2678 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002679 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002680 return (0);
2681}
2682
2683VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2684
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685void
2686ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002687{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002688 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002689
2690 hm->next_override = next;
2691}
2692
Ole Troan944f5482016-05-24 11:56:58 +02002693int
2694ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002695 int options (vlib_buffer_t * b, ip6_header_t * ip,
2696 ip6_hop_by_hop_option_t * opt),
2697 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002698{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002699 ip6_main_t *im = &ip6_main;
2700 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002701
2702 ASSERT (option < ARRAY_LEN (hm->options));
2703
2704 /* Already registered */
2705 if (hm->options[option])
2706 return (-1);
2707
2708 hm->options[option] = options;
2709 hm->trace[option] = trace;
2710
2711 /* Set global variable */
2712 im->hbh_enabled = 1;
2713
2714 return (0);
2715}
2716
2717int
2718ip6_hbh_unregister_option (u8 option)
2719{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002720 ip6_main_t *im = &ip6_main;
2721 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002722
2723 ASSERT (option < ARRAY_LEN (hm->options));
2724
2725 /* Not registered */
2726 if (!hm->options[option])
2727 return (-1);
2728
2729 hm->options[option] = NULL;
2730 hm->trace[option] = NULL;
2731
2732 /* Disable global knob if this was the last option configured */
2733 int i;
2734 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002735 for (i = 0; i < 256; i++)
2736 {
2737 if (hm->options[option])
2738 {
2739 found = true;
2740 break;
2741 }
Ole Troan944f5482016-05-24 11:56:58 +02002742 }
Ole Troan944f5482016-05-24 11:56:58 +02002743 if (!found)
2744 im->hbh_enabled = 0;
2745
2746 return (0);
2747}
2748
Ed Warnickecb9cada2015-12-08 15:45:58 -07002749/* Global IP6 main. */
2750ip6_main_t ip6_main;
2751
2752static clib_error_t *
2753ip6_lookup_init (vlib_main_t * vm)
2754{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002755 ip6_main_t *im = &ip6_main;
2756 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002757 uword i;
2758
Damjan Marion8b3191e2016-11-09 19:54:20 +01002759 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2760 return error;
2761
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2763 {
2764 u32 j, i0, i1;
2765
2766 i0 = i / 32;
2767 i1 = i % 32;
2768
2769 for (j = 0; j < i0; j++)
2770 im->fib_masks[i].as_u32[j] = ~0;
2771
2772 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002773 im->fib_masks[i].as_u32[i0] =
2774 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002775 }
2776
2777 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2778
2779 if (im->lookup_table_nbuckets == 0)
2780 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2781
Dave Barachd7cb1b52016-12-09 09:52:16 -05002782 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002783
2784 if (im->lookup_table_size == 0)
2785 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002786
Dave Barachd7cb1b52016-12-09 09:52:16 -05002787 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2788 "ip6 FIB fwding table",
2789 im->lookup_table_nbuckets, im->lookup_table_size);
2790 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2791 "ip6 FIB non-fwding table",
2792 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002793
Ed Warnickecb9cada2015-12-08 15:45:58 -07002794 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07002795 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2796 FIB_SOURCE_DEFAULT_ROUTE);
2797 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2798 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002799
2800 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002801 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002802 pn = pg_get_node (ip6_lookup_node.index);
2803 pn->unformat_edit = unformat_pg_ip6_header;
2804 }
2805
Ole Troan944f5482016-05-24 11:56:58 +02002806 /* Unless explicitly configured, don't process HBH options */
2807 im->hbh_enabled = 0;
2808
Ed Warnickecb9cada2015-12-08 15:45:58 -07002809 {
2810 icmp6_neighbor_solicitation_header_t p;
2811
2812 memset (&p, 0, sizeof (p));
2813
Dave Barachd7cb1b52016-12-09 09:52:16 -05002814 p.ip.ip_version_traffic_class_and_flow_label =
2815 clib_host_to_net_u32 (0x6 << 28);
2816 p.ip.payload_length =
2817 clib_host_to_net_u16 (sizeof (p) -
2818 STRUCT_OFFSET_OF
2819 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002820 p.ip.protocol = IP_PROTOCOL_ICMP6;
2821 p.ip.hop_limit = 255;
2822 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2823
2824 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2825
Dave Barachd7cb1b52016-12-09 09:52:16 -05002826 p.link_layer_option.header.type =
2827 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2828 p.link_layer_option.header.n_data_u64s =
2829 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002830
2831 vlib_packet_template_init (vm,
2832 &im->discover_neighbor_packet_template,
2833 &p, sizeof (p),
2834 /* alloc chunk size */ 8,
2835 "ip6 neighbor discovery");
2836 }
2837
Dave Barach203c6322016-06-26 10:29:03 -04002838 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002839}
2840
2841VLIB_INIT_FUNCTION (ip6_lookup_init);
2842
Dave Barach75fc8542016-10-11 16:16:02 -04002843void
Dave Barachd7cb1b52016-12-09 09:52:16 -05002844ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
2845 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002846{
2847 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
2848 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002849 ip->as_u8[8] = mac[0] ^ (1 << 1);
2850 ip->as_u8[9] = mac[1];
2851 ip->as_u8[10] = mac[2];
2852 ip->as_u8[11] = 0xFF;
2853 ip->as_u8[12] = 0xFE;
2854 ip->as_u8[13] = mac[3];
2855 ip->as_u8[14] = mac[4];
2856 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002857}
2858
Dave Barach75fc8542016-10-11 16:16:02 -04002859void
Dave Barachd7cb1b52016-12-09 09:52:16 -05002860ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
2861 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002862{
2863 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 mac[0] = ip->as_u8[8] ^ (1 << 1);
2865 mac[1] = ip->as_u8[9];
2866 mac[2] = ip->as_u8[10];
2867 mac[3] = ip->as_u8[13];
2868 mac[4] = ip->as_u8[14];
2869 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002870}
2871
Dave Barach75fc8542016-10-11 16:16:02 -04002872static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07002873test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002874 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002875{
2876 u8 mac[6];
2877 ip6_address_t _a, *a = &_a;
2878
2879 if (unformat (input, "%U", unformat_ethernet_address, mac))
2880 {
2881 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002882 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002883 ip6_ethernet_mac_address_from_link_local_address (mac, a);
2884 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002885 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002886 }
Dave Barach75fc8542016-10-11 16:16:02 -04002887
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888 return 0;
2889}
2890
Billy McFall0683c9c2016-10-13 08:27:31 -04002891/*?
2892 * This command converts the given MAC Address into an IPv6 link-local
2893 * address.
2894 *
2895 * @cliexpar
2896 * Example of how to create an IPv6 link-local address:
2897 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
2898 * Link local address: fe80::14d9:e0ff:fe91:7986
2899 * Original MAC address: 16:d9:e0:91:79:86
2900 * @cliexend
2901?*/
2902/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903VLIB_CLI_COMMAND (test_link_command, static) =
2904{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002905 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04002906 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907 .short_help = "test ip6 link <mac-address>",
2908};
Billy McFall0683c9c2016-10-13 08:27:31 -04002909/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002910
Dave Barachd7cb1b52016-12-09 09:52:16 -05002911int
2912vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002913{
Neale Ranns107e7d42017-04-11 09:55:19 -07002914 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915
Neale Ranns107e7d42017-04-11 09:55:19 -07002916 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002917
Neale Ranns107e7d42017-04-11 09:55:19 -07002918 if (~0 == fib_index)
2919 return VNET_API_ERROR_NO_SUCH_FIB;
2920
Neale Ranns227038a2017-04-21 01:07:59 -07002921 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
2922 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002923
Neale Ranns227038a2017-04-21 01:07:59 -07002924 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925}
2926
2927static clib_error_t *
2928set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002929 unformat_input_t * input,
2930 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002931{
2932 int matched = 0;
2933 u32 table_id = 0;
2934 u32 flow_hash_config = 0;
2935 int rv;
2936
Dave Barachd7cb1b52016-12-09 09:52:16 -05002937 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2938 {
2939 if (unformat (input, "table %d", &table_id))
2940 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002941#define _(a,v) \
2942 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002943 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002944#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002945 else
2946 break;
2947 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002948
2949 if (matched == 0)
2950 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002951 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002952
Ed Warnickecb9cada2015-12-08 15:45:58 -07002953 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
2954 switch (rv)
2955 {
Neale Ranns227038a2017-04-21 01:07:59 -07002956 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957 break;
2958
2959 case -1:
2960 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002961
Ed Warnickecb9cada2015-12-08 15:45:58 -07002962 default:
2963 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2964 break;
2965 }
Dave Barach75fc8542016-10-11 16:16:02 -04002966
Ed Warnickecb9cada2015-12-08 15:45:58 -07002967 return 0;
2968}
2969
Billy McFall0683c9c2016-10-13 08:27:31 -04002970/*?
2971 * Configure the set of IPv6 fields used by the flow hash.
2972 *
2973 * @cliexpar
2974 * @parblock
2975 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04002976 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2977 *
Billy McFall0683c9c2016-10-13 08:27:31 -04002978 * Example of display the configured flow hash:
2979 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002980 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2981 * @::/0
2982 * unicast-ip6-chain
2983 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2984 * [0] [@0]: dpo-drop ip6
2985 * fe80::/10
2986 * unicast-ip6-chain
2987 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2988 * [0] [@2]: dpo-receive
2989 * ff02::1/128
2990 * unicast-ip6-chain
2991 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2992 * [0] [@2]: dpo-receive
2993 * ff02::2/128
2994 * unicast-ip6-chain
2995 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2996 * [0] [@2]: dpo-receive
2997 * ff02::16/128
2998 * unicast-ip6-chain
2999 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3000 * [0] [@2]: dpo-receive
3001 * ff02::1:ff00:0/104
3002 * unicast-ip6-chain
3003 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3004 * [0] [@2]: dpo-receive
3005 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3006 * @::/0
3007 * unicast-ip6-chain
3008 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3009 * [0] [@0]: dpo-drop ip6
3010 * @::a:1:1:0:4/126
3011 * unicast-ip6-chain
3012 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3013 * [0] [@4]: ipv6-glean: af_packet0
3014 * @::a:1:1:0:7/128
3015 * unicast-ip6-chain
3016 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3017 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3018 * fe80::/10
3019 * unicast-ip6-chain
3020 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3021 * [0] [@2]: dpo-receive
3022 * fe80::fe:3eff:fe3e:9222/128
3023 * unicast-ip6-chain
3024 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3025 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3026 * ff02::1/128
3027 * unicast-ip6-chain
3028 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3029 * [0] [@2]: dpo-receive
3030 * ff02::2/128
3031 * unicast-ip6-chain
3032 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3033 * [0] [@2]: dpo-receive
3034 * ff02::16/128
3035 * unicast-ip6-chain
3036 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3037 * [0] [@2]: dpo-receive
3038 * ff02::1:ff00:0/104
3039 * unicast-ip6-chain
3040 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3041 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003042 * @cliexend
3043 * @endparblock
3044?*/
3045/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3047{
3048 .path = "set ip6 flow-hash",
3049 .short_help =
3050 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3051 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052};
Billy McFall0683c9c2016-10-13 08:27:31 -04003053/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003054
3055static clib_error_t *
3056show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003057 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003058{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003059 ip6_main_t *im = &ip6_main;
3060 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003062
Ed Warnickecb9cada2015-12-08 15:45:58 -07003063 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003065 {
3066 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02003067 {
3068
3069 u32 node_index = vlib_get_node (vm,
3070 ip6_local_node.index)->
3071 next_nodes[lm->local_next_by_ip_protocol[i]];
3072 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3073 node_index);
3074 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003075 }
3076 return 0;
3077}
3078
3079
3080
Billy McFall0683c9c2016-10-13 08:27:31 -04003081/*?
3082 * Display the set of protocols handled by the local IPv6 stack.
3083 *
3084 * @cliexpar
3085 * Example of how to display local protocol table:
3086 * @cliexstart{show ip6 local}
3087 * Protocols handled by ip6_local
3088 * 17
3089 * 43
3090 * 58
3091 * 115
3092 * @cliexend
3093?*/
3094/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003095VLIB_CLI_COMMAND (show_ip6_local, static) =
3096{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003097 .path = "show ip6 local",
3098 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003099 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003100};
Billy McFall0683c9c2016-10-13 08:27:31 -04003101/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102
Dave Barachd7cb1b52016-12-09 09:52:16 -05003103int
3104vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3105 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003106{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 vnet_main_t *vnm = vnet_get_main ();
3108 vnet_interface_main_t *im = &vnm->interface_main;
3109 ip6_main_t *ipm = &ip6_main;
3110 ip_lookup_main_t *lm = &ipm->lookup_main;
3111 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003112 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113
3114 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3115 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3116
3117 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3118 return VNET_API_ERROR_NO_SUCH_ENTRY;
3119
3120 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003121 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003122
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003123 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003124
3125 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003126 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003127 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003128 .fp_len = 128,
3129 .fp_proto = FIB_PROTOCOL_IP6,
3130 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003131 };
3132 u32 fib_index;
3133
Dave Barachd7cb1b52016-12-09 09:52:16 -05003134 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3135 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003136
3137
Dave Barachd7cb1b52016-12-09 09:52:16 -05003138 if (table_index != (u32) ~ 0)
3139 {
3140 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003141
Dave Barachd7cb1b52016-12-09 09:52:16 -05003142 dpo_set (&dpo,
3143 DPO_CLASSIFY,
3144 DPO_PROTO_IP6,
3145 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003146
Dave Barachd7cb1b52016-12-09 09:52:16 -05003147 fib_table_entry_special_dpo_add (fib_index,
3148 &pfx,
3149 FIB_SOURCE_CLASSIFY,
3150 FIB_ENTRY_FLAG_NONE, &dpo);
3151 dpo_reset (&dpo);
3152 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003153 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003154 {
3155 fib_table_entry_special_remove (fib_index,
3156 &pfx, FIB_SOURCE_CLASSIFY);
3157 }
3158 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003159
Ed Warnickecb9cada2015-12-08 15:45:58 -07003160 return 0;
3161}
3162
3163static clib_error_t *
3164set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003165 unformat_input_t * input,
3166 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167{
3168 u32 table_index = ~0;
3169 int table_index_set = 0;
3170 u32 sw_if_index = ~0;
3171 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003172
Dave Barachd7cb1b52016-12-09 09:52:16 -05003173 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3174 {
3175 if (unformat (input, "table-index %d", &table_index))
3176 table_index_set = 1;
3177 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3178 vnet_get_main (), &sw_if_index))
3179 ;
3180 else
3181 break;
3182 }
Dave Barach75fc8542016-10-11 16:16:02 -04003183
Ed Warnickecb9cada2015-12-08 15:45:58 -07003184 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003185 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003186
Ed Warnickecb9cada2015-12-08 15:45:58 -07003187 if (sw_if_index == ~0)
3188 return clib_error_return (0, "interface / subif must be specified");
3189
3190 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3191
3192 switch (rv)
3193 {
3194 case 0:
3195 break;
3196
3197 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3198 return clib_error_return (0, "No such interface");
3199
3200 case VNET_API_ERROR_NO_SUCH_ENTRY:
3201 return clib_error_return (0, "No such classifier table");
3202 }
3203 return 0;
3204}
3205
Billy McFall0683c9c2016-10-13 08:27:31 -04003206/*?
3207 * Assign a classification table to an interface. The classification
3208 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3209 * commands. Once the table is create, use this command to filter packets
3210 * on an interface.
3211 *
3212 * @cliexpar
3213 * Example of how to assign a classification table to an interface:
3214 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3215?*/
3216/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003217VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3218{
3219 .path = "set ip6 classify",
3220 .short_help =
3221 "set ip6 classify intfc <interface> table-index <classify-idx>",
3222 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003223};
Billy McFall0683c9c2016-10-13 08:27:31 -04003224/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003225
3226static clib_error_t *
3227ip6_config (vlib_main_t * vm, unformat_input_t * input)
3228{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003229 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003230 uword heapsize = 0;
3231 u32 tmp;
3232 u32 nbuckets = 0;
3233
Dave Barachd7cb1b52016-12-09 09:52:16 -05003234 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3235 {
3236 if (unformat (input, "hash-buckets %d", &tmp))
3237 nbuckets = tmp;
Neale Ranns1ec36522017-11-29 05:20:37 -08003238 else if (unformat (input, "heap-size %U",
3239 unformat_memory_size, &heapsize))
3240 ;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003241 else
3242 return clib_error_return (0, "unknown input '%U'",
3243 format_unformat_error, input);
3244 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003245
3246 im->lookup_table_nbuckets = nbuckets;
3247 im->lookup_table_size = heapsize;
3248
3249 return 0;
3250}
3251
3252VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003253
3254/*
3255 * fd.io coding-style-patch-verification: ON
3256 *
3257 * Local Variables:
3258 * eval: (c-set-style "gnu")
3259 * End:
3260 */