blob: 8ae08a01cf2023aa8d5e86433114e219bf73a4fd [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>
53
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053054/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
55#define OI_DECAP 0x80000000
56
Billy McFall0683c9c2016-10-13 08:27:31 -040057/**
58 * @file
59 * @brief IPv6 Forwarding.
60 *
61 * This file contains the source code for IPv6 forwarding.
62 */
63
Pierre Pfister0febaf12016-06-08 12:23:21 +010064void
65ip6_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050066 vlib_node_runtime_t * node,
67 vlib_frame_t * frame,
68 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010069
Damjan Marionaca64c92016-04-13 09:48:56 +020070always_inline uword
71ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050072 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070073{
Dave Barachd7cb1b52016-12-09 09:52:16 -050074 ip6_main_t *im = &ip6_main;
75 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
76 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020078 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 from = vlib_frame_vector_args (frame);
81 n_left_from = frame->n_vectors;
82 next = node->cached_next_index;
83
84 while (n_left_from > 0)
85 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050086 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
88 while (n_left_from >= 4 && n_left_to_next >= 2)
89 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010091 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050093 ip6_header_t *ip0, *ip1;
94 ip6_address_t *dst_addr0, *dst_addr1;
95 u32 fib_index0, fib_index1;
96 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010097 const dpo_id_t *dpo0, *dpo1;
98 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
100 /* Prefetch next iteration. */
101 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
104 p2 = vlib_get_buffer (vm, from[2]);
105 p3 = vlib_get_buffer (vm, from[3]);
106
107 vlib_prefetch_buffer_header (p2, LOAD);
108 vlib_prefetch_buffer_header (p3, LOAD);
109 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
110 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
111 }
112
113 pi0 = to_next[0] = from[0];
114 pi1 = to_next[1] = from[1];
115
116 p0 = vlib_get_buffer (vm, pi0);
117 p1 = vlib_get_buffer (vm, pi1);
118
119 ip0 = vlib_buffer_get_current (p0);
120 ip1 = vlib_buffer_get_current (p1);
121
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100122 dst_addr0 = &ip0->dst_address;
123 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200124
Dave Barachd7cb1b52016-12-09 09:52:16 -0500125 fib_index0 =
126 vec_elt (im->fib_index_by_sw_if_index,
127 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
128 fib_index1 =
129 vec_elt (im->fib_index_by_sw_if_index,
130 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
133 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
134 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
135 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100137 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
138 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100140 lb0 = load_balance_get (lbi0);
141 lb1 = load_balance_get (lbi1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700142 ASSERT (lb0->lb_n_buckets > 0);
143 ASSERT (lb1->lb_n_buckets > 0);
144 ASSERT (is_pow2 (lb0->lb_n_buckets));
145 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148
Dave Barachd7cb1b52016-12-09 09:52:16 -0500149 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
150 {
151 flow_hash_config0 = lb0->lb_hash_config;
152 vnet_buffer (p0)->ip.flow_hash =
153 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700154 dpo0 =
155 load_balance_get_fwd_bucket (lb0,
156 (vnet_buffer (p0)->ip.flow_hash &
157 (lb0->lb_n_buckets_minus_1)));
158 }
159 else
160 {
161 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500162 }
163 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
164 {
165 flow_hash_config1 = lb1->lb_hash_config;
166 vnet_buffer (p1)->ip.flow_hash =
167 ip6_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700168 dpo1 =
169 load_balance_get_fwd_bucket (lb1,
170 (vnet_buffer (p1)->ip.flow_hash &
171 (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500172 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700173 else
174 {
175 dpo1 = load_balance_get_bucket_i (lb1, 0);
176 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100177 next0 = dpo0->dpoi_next_node;
178 next1 = dpo1->dpoi_next_node;
179
180 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 if (PREDICT_FALSE
182 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100183 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500184 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100185 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
186 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 if (PREDICT_FALSE
188 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100189 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100191 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
192 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100193 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
194 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach75fc8542016-10-11 16:16:02 -0400196 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200197 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400198 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200199 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
201 from += 2;
202 to_next += 2;
203 n_left_to_next -= 2;
204 n_left_from -= 2;
205
Dave Barachd7cb1b52016-12-09 09:52:16 -0500206 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500208 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 switch (wrong_next)
210 {
211 case 1:
212 /* A B A */
213 to_next[-2] = pi1;
214 to_next -= 1;
215 n_left_to_next += 1;
216 vlib_set_next_frame_buffer (vm, node, next0, pi0);
217 break;
218
219 case 2:
220 /* A A B */
221 to_next -= 1;
222 n_left_to_next += 1;
223 vlib_set_next_frame_buffer (vm, node, next1, pi1);
224 break;
225
226 case 3:
227 /* A B C */
228 to_next -= 2;
229 n_left_to_next += 2;
230 vlib_set_next_frame_buffer (vm, node, next0, pi0);
231 vlib_set_next_frame_buffer (vm, node, next1, pi1);
232 if (next0 == next1)
233 {
234 /* A B B */
235 vlib_put_next_frame (vm, node, next, n_left_to_next);
236 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 vlib_get_next_frame (vm, node, next, to_next,
238 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 }
240 }
241 }
242 }
Dave Barach75fc8542016-10-11 16:16:02 -0400243
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 while (n_left_from > 0 && n_left_to_next > 0)
245 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500246 vlib_buffer_t *p0;
247 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500250 load_balance_t *lb0;
251 ip6_address_t *dst_addr0;
252 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100253 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
255 pi0 = from[0];
256 to_next[0] = pi0;
257
258 p0 = vlib_get_buffer (vm, pi0);
259
260 ip0 = vlib_buffer_get_current (p0);
261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200263
Dave Barachd7cb1b52016-12-09 09:52:16 -0500264 fib_index0 =
265 vec_elt (im->fib_index_by_sw_if_index,
266 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
267 fib_index0 =
268 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
269 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100271 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100273 lb0 = load_balance_get (lbi0);
Neale Ranns227038a2017-04-21 01:07:59 -0700274 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
Dave Barachd7cb1b52016-12-09 09:52:16 -0500276 vnet_buffer (p0)->ip.flow_hash = 0;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700277 ASSERT (lb0->lb_n_buckets > 0);
278 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
Dave Barachd7cb1b52016-12-09 09:52:16 -0500280 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
281 {
282 flow_hash_config0 = lb0->lb_hash_config;
283 vnet_buffer (p0)->ip.flow_hash =
284 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700285 dpo0 =
286 load_balance_get_fwd_bucket (lb0,
287 (vnet_buffer (p0)->ip.flow_hash &
288 (lb0->lb_n_buckets_minus_1)));
289 }
290 else
291 {
292 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
Dave Barachd7cb1b52016-12-09 09:52:16 -0500295 dpo0 = load_balance_get_bucket_i (lb0,
296 (vnet_buffer (p0)->ip.flow_hash &
297 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299
Shwetha57fc8542016-09-27 08:04:05 +0100300 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301 if (PREDICT_FALSE
302 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100303 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100305 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
306 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100307 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
Dave Barach75fc8542016-10-11 16:16:02 -0400309 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200310 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311
312 from += 1;
313 to_next += 1;
314 n_left_to_next -= 1;
315 n_left_from -= 1;
316
317 if (PREDICT_FALSE (next0 != next))
318 {
319 n_left_to_next += 1;
320 vlib_put_next_frame (vm, node, next, n_left_to_next);
321 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500322 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323 to_next[0] = pi0;
324 to_next += 1;
325 n_left_to_next -= 1;
326 }
327 }
328
329 vlib_put_next_frame (vm, node, next, n_left_to_next);
330 }
331
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100332 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100334
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 return frame->n_vectors;
336}
337
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338static void
339ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
340 ip6_main_t * im, u32 fib_index,
341 ip_interface_address_t * a)
342{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500343 ip_lookup_main_t *lm = &im->lookup_main;
344 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100345 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500346 .fp_len = a->address_length,
347 .fp_proto = FIB_PROTOCOL_IP6,
348 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100349 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500352 {
Neale Ranns7a272742017-05-30 02:08:14 -0700353 fib_table_entry_update_one_path (fib_index,
354 &pfx,
355 FIB_SOURCE_INTERFACE,
356 (FIB_ENTRY_FLAG_CONNECTED |
357 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700358 DPO_PROTO_IP6,
Neale Ranns7a272742017-05-30 02:08:14 -0700359 /* No next-hop address */
360 NULL, sw_if_index,
361 /* invalid FIB index */
362 ~0, 1,
363 /* no label stack */
364 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500365 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100367 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500369 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500371 lm->classify_table_index_by_sw_if_index[sw_if_index];
372 if (classify_table_index != (u32) ~ 0)
373 {
374 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 dpo_set (&dpo,
377 DPO_CLASSIFY,
378 DPO_PROTO_IP6,
379 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100380
Dave Barachd7cb1b52016-12-09 09:52:16 -0500381 fib_table_entry_special_dpo_add (fib_index,
382 &pfx,
383 FIB_SOURCE_CLASSIFY,
384 FIB_ENTRY_FLAG_NONE, &dpo);
385 dpo_reset (&dpo);
386 }
387 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100388
Neale Rannsf12a83f2017-04-18 09:09:40 -0700389 fib_table_entry_update_one_path (fib_index, &pfx,
390 FIB_SOURCE_INTERFACE,
391 (FIB_ENTRY_FLAG_CONNECTED |
392 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700393 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700394 &pfx.fp_addr,
395 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397}
398
399static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100400ip6_del_interface_routes (ip6_main_t * im,
401 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500402 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500404 fib_prefix_t pfx = {
405 .fp_len = address_length,
406 .fp_proto = FIB_PROTOCOL_IP6,
407 .fp_addr.ip6 = *address,
408 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
Dave Barachd7cb1b52016-12-09 09:52:16 -0500410 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500412 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100413
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 }
415
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416 pfx.fp_len = 128;
417 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418}
419
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100420void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500421ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500423 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100425 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100427 /*
428 * enable/disable only on the 1<->0 transition
429 */
430 if (is_enable)
431 {
432 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500433 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434 }
435 else
436 {
Neale Ranns75152282017-01-09 01:00:45 -0800437 /* The ref count is 0 when an address is removed from an interface that has
438 * no address - this is not a ciritical error */
439 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
440 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500441 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100442 }
443
Neale Ranns630198f2017-05-22 09:20:20 -0400444 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
445 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446
Neale Ranns630198f2017-05-22 09:20:20 -0400447 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
448 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100449}
450
Neale Rannsdf089a82016-10-02 16:39:06 +0100451/* get first interface address */
452ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800453ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100454{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455 ip_lookup_main_t *lm = &im->lookup_main;
456 ip_interface_address_t *ia = 0;
457 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100458
Dave Barachd7cb1b52016-12-09 09:52:16 -0500459 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100460 foreach_ip_interface_address (lm, ia, sw_if_index,
461 1 /* honor unnumbered */,
462 ({
463 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
464 result = a;
465 break;
466 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100468 return result;
469}
470
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471clib_error_t *
472ip6_add_del_interface_address (vlib_main_t * vm,
473 u32 sw_if_index,
474 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500475 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 vnet_main_t *vnm = vnet_get_main ();
478 ip6_main_t *im = &ip6_main;
479 ip_lookup_main_t *lm = &im->lookup_main;
480 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483
Pavel Kotucek57808982017-08-02 08:20:19 +0200484 /* local0 interface doesn't support IP addressing */
485 if (sw_if_index == 0)
486 {
487 return
488 clib_error_create ("local0 interface doesn't support IP addressing");
489 }
490
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000492 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
493
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 ip6_addr_fib_init (&ip6_af, address,
495 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
496 vec_add1 (addr_fib, ip6_af);
497
498 {
499 uword elts_before = pool_elts (lm->if_address_pool);
500
501 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 if (error)
504 goto done;
505
506 /* Pool did not grow: add duplicate address. */
507 if (elts_before == pool_elts (lm->if_address_pool))
508 goto done;
509 }
510
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000512
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100513 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500514 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100515 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500516 ip6_add_interface_routes (vnm, sw_if_index,
517 im, ip6_af.fib_index,
518 pool_elt_at_index (lm->if_address_pool,
519 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520
521 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500522 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523 vec_foreach (cb, im->add_del_interface_address_callbacks)
524 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 }
527
Dave Barachd7cb1b52016-12-09 09:52:16 -0500528done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 vec_free (addr_fib);
530 return error;
531}
532
533clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 ip6_main_t *im = &ip6_main;
537 ip_interface_address_t *ia;
538 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539 u32 is_admin_up, fib_index;
540
541 /* Fill in lookup tables with default table (0). */
542 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
543
Dave Barachd7cb1b52016-12-09 09:52:16 -0500544 vec_validate_init_empty (im->
545 lookup_main.if_address_pool_index_by_sw_if_index,
546 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547
548 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
549
550 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
551
Dave Barachd7cb1b52016-12-09 09:52:16 -0500552 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400553 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 0 /* honor unnumbered */,
555 ({
556 a = ip_interface_address_get_address (&im->lookup_main, ia);
557 if (is_admin_up)
558 ip6_add_interface_routes (vnm, sw_if_index,
559 im, fib_index,
560 ia);
561 else
562 ip6_del_interface_routes (im, fib_index,
563 a, ia->address_length);
564 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500565 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566
567 return 0;
568}
569
570VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
571
Dave Barachd6534602016-06-14 18:38:02 -0400572/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500573/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100574VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
575{
576 .arc_name = "ip6-unicast",
577 .start_nodes = VNET_FEATURES ("ip6-input"),
578 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
579};
580
Dave Barachd7cb1b52016-12-09 09:52:16 -0500581VNET_FEATURE_INIT (ip6_flow_classify, static) =
582{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100583 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700584 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100585 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700586};
587
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588VNET_FEATURE_INIT (ip6_inacl, static) =
589{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100590 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400591 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100592 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400593};
594
Dave Barachd7cb1b52016-12-09 09:52:16 -0500595VNET_FEATURE_INIT (ip6_policer_classify, static) =
596{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100597 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700598 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100599 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700600};
601
Dave Barachd7cb1b52016-12-09 09:52:16 -0500602VNET_FEATURE_INIT (ip6_ipsec, static) =
603{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100604 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400605 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100606 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400607};
608
Dave Barachd7cb1b52016-12-09 09:52:16 -0500609VNET_FEATURE_INIT (ip6_l2tp, static) =
610{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100611 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400612 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100613 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400614};
615
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616VNET_FEATURE_INIT (ip6_vpath, static) =
617{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100618 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400619 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500620 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
621};
622
623VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
624{
625 .arc_name = "ip6-unicast",
626 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100627 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400628};
629
Dave Barachd7cb1b52016-12-09 09:52:16 -0500630VNET_FEATURE_INIT (ip6_drop, static) =
631{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100632 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100633 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400634 .runs_before = VNET_FEATURES ("ip6-lookup"),
635};
636
637VNET_FEATURE_INIT (ip6_lookup, static) =
638{
639 .arc_name = "ip6-unicast",
640 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642};
643
Dave Barachd6534602016-06-14 18:38:02 -0400644/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100645VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
646{
647 .arc_name = "ip6-multicast",
648 .start_nodes = VNET_FEATURES ("ip6-input"),
649 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
650};
651
652VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
653 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400654 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000655 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400656};
657
Damjan Marion8b3191e2016-11-09 19:54:20 +0100658VNET_FEATURE_INIT (ip6_drop_mc, static) = {
659 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100660 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400661 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
662};
663
664VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
665 .arc_name = "ip6-multicast",
666 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100667 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100668};
Dave Barach5331c722016-08-17 11:54:30 -0400669
670/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100671VNET_FEATURE_ARC_INIT (ip6_output, static) =
672{
673 .arc_name = "ip6-output",
674 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
675 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400676};
677
Matus Fabian08a6f012016-11-15 06:08:51 -0800678VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
679 .arc_name = "ip6-output",
680 .node_name = "ipsec-output-ip6",
681 .runs_before = VNET_FEATURES ("interface-output"),
682};
683
Damjan Marion8b3191e2016-11-09 19:54:20 +0100684VNET_FEATURE_INIT (ip6_interface_output, static) = {
685 .arc_name = "ip6-output",
686 .node_name = "interface-output",
687 .runs_before = 0, /* not before any other features */
688};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500689/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400690
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500692ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700694 ip6_main_t *im = &ip6_main;
695
696 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
697 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
698
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200699 if (!is_add)
700 {
701 /* Ensure that IPv6 is disabled */
702 ip6_main_t *im6 = &ip6_main;
703 ip_lookup_main_t *lm6 = &im6->lookup_main;
704 ip_interface_address_t *ia = 0;
705 ip6_address_t *address;
706 vlib_main_t *vm = vlib_get_main ();
707
708 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
709 /* *INDENT-OFF* */
710 foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* honor unnumbered */,
711 ({
712 address = ip_interface_address_get_address (lm6, ia);
713 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
714 }));
715 /* *INDENT-ON* */
716 ip6_mfib_interface_enable_disable (sw_if_index, 0);
717 }
718
Damjan Marion8b3191e2016-11-09 19:54:20 +0100719 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
720 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
723 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725 return /* no error */ 0;
726}
727
728VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
729
Damjan Marionaca64c92016-04-13 09:48:56 +0200730static uword
731ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200733{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100734 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200735}
736
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739/* *INDENT-OFF* */
740VLIB_REGISTER_NODE (ip6_lookup_node) =
741{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 .function = ip6_lookup,
743 .name = "ip6-lookup",
744 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100745 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200746 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200747 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500749/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750
Dave Barachd7cb1b52016-12-09 09:52:16 -0500751VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200752
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100753always_inline uword
754ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500755 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200756{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500757 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
758 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200760 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500761 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100762
763 from = vlib_frame_vector_args (frame);
764 n_left_from = frame->n_vectors;
765 next = node->cached_next_index;
766
767 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500768 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100769
770 while (n_left_from > 0)
771 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500772 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100773
Dave Barach75fc8542016-10-11 16:16:02 -0400774
Neale Ranns2be95c12016-11-19 13:50:04 +0000775 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500776 {
777 ip_lookup_next_t next0, next1;
778 const load_balance_t *lb0, *lb1;
779 vlib_buffer_t *p0, *p1;
780 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
781 const ip6_header_t *ip0, *ip1;
782 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000783
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 /* Prefetch next iteration. */
785 {
786 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000787
Dave Barachd7cb1b52016-12-09 09:52:16 -0500788 p2 = vlib_get_buffer (vm, from[2]);
789 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000790
Dave Barachd7cb1b52016-12-09 09:52:16 -0500791 vlib_prefetch_buffer_header (p2, STORE);
792 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000793
Dave Barachd7cb1b52016-12-09 09:52:16 -0500794 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
795 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
796 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000797
Dave Barachd7cb1b52016-12-09 09:52:16 -0500798 pi0 = to_next[0] = from[0];
799 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000800
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 from += 2;
802 n_left_from -= 2;
803 to_next += 2;
804 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000805
Dave Barachd7cb1b52016-12-09 09:52:16 -0500806 p0 = vlib_get_buffer (vm, pi0);
807 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000808
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 ip0 = vlib_buffer_get_current (p0);
810 ip1 = vlib_buffer_get_current (p1);
811 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
812 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000813
Dave Barachd7cb1b52016-12-09 09:52:16 -0500814 lb0 = load_balance_get (lbi0);
815 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000816
Dave Barachd7cb1b52016-12-09 09:52:16 -0500817 /*
818 * this node is for via FIBs we can re-use the hash value from the
819 * to node if present.
820 * We don't want to use the same hash value at each level in the recursion
821 * graph as that would lead to polarisation
822 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000823 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000824
Dave Barachd7cb1b52016-12-09 09:52:16 -0500825 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
826 {
827 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
828 {
829 hc0 = vnet_buffer (p0)->ip.flow_hash =
830 vnet_buffer (p0)->ip.flow_hash >> 1;
831 }
832 else
833 {
834 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000835 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500836 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700837 dpo0 =
838 load_balance_get_fwd_bucket (lb0,
839 (hc0 &
840 lb0->lb_n_buckets_minus_1));
841 }
842 else
843 {
844 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 }
846 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
847 {
848 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
849 {
850 hc1 = vnet_buffer (p1)->ip.flow_hash =
851 vnet_buffer (p1)->ip.flow_hash >> 1;
852 }
853 else
854 {
855 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000856 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700858 dpo1 =
859 load_balance_get_fwd_bucket (lb1,
860 (hc1 &
861 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700863 else
864 {
865 dpo1 = load_balance_get_bucket_i (lb1, 0);
866 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000867
Dave Barachd7cb1b52016-12-09 09:52:16 -0500868 next0 = dpo0->dpoi_next_node;
869 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000870
Dave Barachd7cb1b52016-12-09 09:52:16 -0500871 /* Only process the HBH Option Header if explicitly configured to do so */
872 if (PREDICT_FALSE
873 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
874 {
875 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
876 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
877 }
878 /* Only process the HBH Option Header if explicitly configured to do so */
879 if (PREDICT_FALSE
880 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
881 {
882 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
883 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
884 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000885
Dave Barachd7cb1b52016-12-09 09:52:16 -0500886 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
887 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000888
Dave Barachd7cb1b52016-12-09 09:52:16 -0500889 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200890 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500891 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200892 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000893
Dave Barachd7cb1b52016-12-09 09:52:16 -0500894 vlib_validate_buffer_enqueue_x2 (vm, node, next,
895 to_next, n_left_to_next,
896 pi0, pi1, next0, next1);
897 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000898
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100899 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500900 {
901 ip_lookup_next_t next0;
902 const load_balance_t *lb0;
903 vlib_buffer_t *p0;
904 u32 pi0, lbi0, hc0;
905 const ip6_header_t *ip0;
906 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100907
Dave Barachd7cb1b52016-12-09 09:52:16 -0500908 pi0 = from[0];
909 to_next[0] = pi0;
910 from += 1;
911 to_next += 1;
912 n_left_to_next -= 1;
913 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917 ip0 = vlib_buffer_get_current (p0);
918 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100919
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000922 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500923 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
924 {
925 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
926 {
927 hc0 = vnet_buffer (p0)->ip.flow_hash =
928 vnet_buffer (p0)->ip.flow_hash >> 1;
929 }
930 else
931 {
932 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000933 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700935 dpo0 =
936 load_balance_get_fwd_bucket (lb0,
937 (hc0 &
938 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700940 else
941 {
942 dpo0 = load_balance_get_bucket_i (lb0, 0);
943 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100944
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945 next0 = dpo0->dpoi_next_node;
946 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000947
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948 /* Only process the HBH Option Header if explicitly configured to do so */
949 if (PREDICT_FALSE
950 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
951 {
952 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
953 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
954 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000955
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200957 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
Dave Barachd7cb1b52016-12-09 09:52:16 -0500959 vlib_validate_buffer_enqueue_x1 (vm, node, next,
960 to_next, n_left_to_next,
961 pi0, next0);
962 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100963
964 vlib_put_next_frame (vm, node, next, n_left_to_next);
965 }
966
967 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200968}
969
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970/* *INDENT-OFF* */
971VLIB_REGISTER_NODE (ip6_load_balance_node) =
972{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100973 .function = ip6_load_balance,
974 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200975 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200976 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100977 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200978};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500979/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200980
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200982
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983typedef struct
984{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985 /* Adjacency taken. */
986 u32 adj_index;
987 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500988 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
990 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 u8 packet_data[128 - 1 * sizeof (u32)];
992}
993ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994
John Lo2b81eb82017-01-30 13:12:10 -0500995u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100998 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
999 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001000 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001001 uword indent = format_get_indent (s);
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003 s = format (s, "%U%U",
1004 format_white_space, indent,
1005 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001006 return s;
1007}
1008
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009static u8 *
1010format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001011{
1012 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1013 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 uword indent = format_get_indent (s);
1016
John Loac8146c2016-09-27 17:44:02 -04001017 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001018 t->fib_index, t->adj_index, t->flow_hash);
1019 s = format (s, "\n%U%U",
1020 format_white_space, indent,
1021 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001022 return s;
1023}
Pierre Pfister0febaf12016-06-08 12:23:21 +01001024
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026static u8 *
1027format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001028{
1029 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1030 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001032 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001034 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 t->fib_index, t->adj_index, format_ip_adjacency,
1036 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001037 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001038 format_white_space, indent,
1039 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001040 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041 return s;
1042}
1043
1044/* Common trace function for all ip6-forward next nodes. */
1045void
1046ip6_forward_next_trace (vlib_main_t * vm,
1047 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001048 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001050 u32 *from, n_left;
1051 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052
1053 n_left = frame->n_vectors;
1054 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001055
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056 while (n_left >= 4)
1057 {
1058 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001059 vlib_buffer_t *b0, *b1;
1060 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061
1062 /* Prefetch next iteration. */
1063 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1064 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1065
1066 bi0 = from[0];
1067 bi1 = from[1];
1068
1069 b0 = vlib_get_buffer (vm, bi0);
1070 b1 = vlib_get_buffer (vm, bi1);
1071
1072 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1073 {
1074 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1075 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001076 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1077 t0->fib_index =
1078 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1079 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1080 vec_elt (im->fib_index_by_sw_if_index,
1081 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001082
Damjan Marionf1213b82016-03-13 02:22:06 +01001083 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001084 vlib_buffer_get_current (b0),
1085 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086 }
1087 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1088 {
1089 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1090 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001091 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1092 t1->fib_index =
1093 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1094 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1095 vec_elt (im->fib_index_by_sw_if_index,
1096 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001097
Damjan Marionf1213b82016-03-13 02:22:06 +01001098 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001099 vlib_buffer_get_current (b1),
1100 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101 }
1102 from += 2;
1103 n_left -= 2;
1104 }
1105
1106 while (n_left >= 1)
1107 {
1108 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 vlib_buffer_t *b0;
1110 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111
1112 bi0 = from[0];
1113
1114 b0 = vlib_get_buffer (vm, bi0);
1115
1116 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1117 {
1118 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1119 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001120 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1121 t0->fib_index =
1122 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1123 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1124 vec_elt (im->fib_index_by_sw_if_index,
1125 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001126
Damjan Marionf1213b82016-03-13 02:22:06 +01001127 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 vlib_buffer_get_current (b0),
1129 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130 }
1131 from += 1;
1132 n_left -= 1;
1133 }
1134}
1135
1136static uword
1137ip6_drop_or_punt (vlib_main_t * vm,
1138 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 vlib_frame_t * frame, ip6_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001141 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 uword n_packets = frame->n_vectors;
1143
Dave Barachd7cb1b52016-12-09 09:52:16 -05001144 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 /* stride */ 1,
1146 n_packets,
1147 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 ip6_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149
1150 if (node->flags & VLIB_NODE_FLAG_TRACE)
1151 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1152
1153 return n_packets;
1154}
1155
1156static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1158{
1159 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1160}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161
1162static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1164{
1165 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1166}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167
Dave Barachd7cb1b52016-12-09 09:52:16 -05001168/* *INDENT-OFF* */
1169VLIB_REGISTER_NODE (ip6_drop_node, static) =
1170{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001171 .function = ip6_drop,
1172 .name = "ip6-drop",
1173 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176 .next_nodes =
1177 {
1178 [0] = "error-drop",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001183
Dave Barachd7cb1b52016-12-09 09:52:16 -05001184/* *INDENT-OFF* */
1185VLIB_REGISTER_NODE (ip6_punt_node, static) =
1186{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 .function = ip6_punt,
1188 .name = "ip6-punt",
1189 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001192 .next_nodes =
1193 {
1194 [0] = "error-punt",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001196/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001199
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001201u16
1202ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1203 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204{
1205 ip_csum_t sum0;
1206 u16 sum16, payload_length_host_byte_order;
1207 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001208 u32 headers_size = sizeof (ip0[0]);
1209 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001212 *bogus_lengthp = 0;
1213
1214 /* Initialize checksum with ip header. */
1215 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1216 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1217 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001218
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1220 {
1221 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 clib_mem_unaligned (&ip0->
1223 src_address.as_uword[i],
1224 uword));
1225 sum0 =
1226 ip_csum_with_carry (sum0,
1227 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1228 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229 }
1230
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301231 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1232 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001233 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001235 u32 skip_bytes;
1236 ip6_hop_by_hop_ext_t *ext_hdr =
1237 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238
1239 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301240 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1241 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001242
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1244 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001245
Dave Barachd7cb1b52016-12-09 09:52:16 -05001246 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001248 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
1250 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001251 if (p0 && n_this_buffer + headers_size > p0->current_length)
1252 n_this_buffer =
1253 p0->current_length >
1254 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255 while (1)
1256 {
1257 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1258 n_bytes_left -= n_this_buffer;
1259 if (n_bytes_left == 0)
1260 break;
1261
1262 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001263 {
1264 *bogus_lengthp = 1;
1265 return 0xfefe;
1266 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267 p0 = vlib_get_buffer (vm, p0->next_buffer);
1268 data_this_buffer = vlib_buffer_get_current (p0);
1269 n_this_buffer = p0->current_length;
1270 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001273
1274 return sum16;
1275}
1276
Dave Barachd7cb1b52016-12-09 09:52:16 -05001277u32
1278ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001280 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1281 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282 u16 sum16;
1283 int bogus_length;
1284
1285 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1286 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1287 || ip0->protocol == IP_PROTOCOL_ICMP6
1288 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 udp0 = (void *) (ip0 + 1);
1292 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1293 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001294 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1295 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296 return p0->flags;
1297 }
1298
1299 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1300
Damjan Marion213b5aa2017-07-13 21:19:27 +02001301 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1302 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303
1304 return p0->flags;
1305}
1306
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301307/**
1308 * @brief returns number of links on which src is reachable.
1309 */
1310always_inline int
1311ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1312{
1313 const load_balance_t *lb0;
1314 index_t lbi;
1315
1316 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1317 vnet_buffer
1318 (b)->sw_if_index[VLIB_RX],
1319 &i->src_address);
1320
1321 lb0 = load_balance_get (lbi);
1322
1323 return (fib_urpf_check_size (lb0->lb_urpf));
1324}
1325
Ed Warnickecb9cada2015-12-08 15:45:58 -07001326static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001327ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001329 ip6_main_t *im = &ip6_main;
1330 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001331 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001332 u32 *from, *to_next, n_left_from, n_left_to_next;
1333 vlib_node_runtime_t *error_node =
1334 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335
1336 from = vlib_frame_vector_args (frame);
1337 n_left_from = frame->n_vectors;
1338 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001339
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340 if (node->flags & VLIB_NODE_FLAG_TRACE)
1341 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1342
1343 while (n_left_from > 0)
1344 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001345 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346
1347 while (n_left_from >= 4 && n_left_to_next >= 2)
1348 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001349 vlib_buffer_t *p0, *p1;
1350 ip6_header_t *ip0, *ip1;
1351 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001352 u32 pi0, ip_len0, udp_len0, flags0, next0;
1353 u32 pi1, ip_len1, udp_len1, flags1, next1;
1354 i32 len_diff0, len_diff1;
1355 u8 error0, type0, good_l4_checksum0;
1356 u8 error1, type1, good_l4_checksum1;
Shwethab78292e2016-09-13 11:51:00 +01001357 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001358
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359 pi0 = to_next[0] = from[0];
1360 pi1 = to_next[1] = from[1];
1361 from += 2;
1362 n_left_from -= 2;
1363 to_next += 2;
1364 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001365
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366 p0 = vlib_get_buffer (vm, pi0);
1367 p1 = vlib_get_buffer (vm, pi1);
1368
1369 ip0 = vlib_buffer_get_current (p0);
1370 ip1 = vlib_buffer_get_current (p1);
1371
Damjan Marion072401e2017-07-13 18:53:27 +02001372 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1373 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001374
Ed Warnickecb9cada2015-12-08 15:45:58 -07001375 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1376 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1377
1378 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1379 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1380
1381 flags0 = p0->flags;
1382 flags1 = p1->flags;
1383
Damjan Marion213b5aa2017-07-13 21:19:27 +02001384 good_l4_checksum0 =
1385 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1386 good_l4_checksum1 =
1387 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001388 len_diff0 = 0;
1389 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390
Dave Barachd7cb1b52016-12-09 09:52:16 -05001391 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1392 IP_PROTOCOL_UDP,
1393 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001394 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001395 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001396 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001397 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1398 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001399 /* Verify UDP length. */
1400 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1401 udp_len0 = clib_net_to_host_u16 (udp0->length);
1402 len_diff0 = ip_len0 - udp_len0;
1403 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001404 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1405 IP_PROTOCOL_UDP,
1406 &udp_offset1)))
Shwethab78292e2016-09-13 11:51:00 +01001407 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001408 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001409 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001410 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1411 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001412 /* Verify UDP length. */
1413 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1414 udp_len1 = clib_net_to_host_u16 (udp1->length);
1415 len_diff1 = ip_len1 - udp_len1;
1416 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417
1418 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1419 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1420
Ed Warnickecb9cada2015-12-08 15:45:58 -07001421 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1422 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1423
1424 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001425 && !good_l4_checksum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001426 && !(flags0 &
1427 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001428 {
1429 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1430 good_l4_checksum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001431 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432 }
1433 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001434 && !good_l4_checksum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001435 && !(flags1 &
1436 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437 {
1438 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1439 good_l4_checksum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001440 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441 }
1442
1443 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1444
1445 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1446 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1447
Dave Barachd7cb1b52016-12-09 09:52:16 -05001448 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1449 IP6_ERROR_UDP_CHECKSUM);
1450 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1451 IP6_ERROR_ICMP_CHECKSUM);
1452 error0 =
1453 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1454 error1 =
1455 (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001456
1457 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001458 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001459 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1460 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001461 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001462 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301463 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001464 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001465 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001466 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1467 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001468 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001469 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301470 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001471 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001472 }
1473
Dave Barachd7cb1b52016-12-09 09:52:16 -05001474 next0 =
1475 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1476 next1 =
1477 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001478
1479 p0->error = error_node->errors[error0];
1480 p1->error = error_node->errors[error1];
1481
1482 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1483 to_next, n_left_to_next,
1484 pi0, pi1, next0, next1);
1485 }
1486
1487 while (n_left_from > 0 && n_left_to_next > 0)
1488 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001489 vlib_buffer_t *p0;
1490 ip6_header_t *ip0;
1491 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492 u32 pi0, ip_len0, udp_len0, flags0, next0;
1493 i32 len_diff0;
1494 u8 error0, type0, good_l4_checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001495 u32 udp_offset0;
Dave Barach75fc8542016-10-11 16:16:02 -04001496
Ed Warnickecb9cada2015-12-08 15:45:58 -07001497 pi0 = to_next[0] = from[0];
1498 from += 1;
1499 n_left_from -= 1;
1500 to_next += 1;
1501 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001502
Ed Warnickecb9cada2015-12-08 15:45:58 -07001503 p0 = vlib_get_buffer (vm, pi0);
1504
1505 ip0 = vlib_buffer_get_current (p0);
1506
Damjan Marion072401e2017-07-13 18:53:27 +02001507 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001508
Ed Warnickecb9cada2015-12-08 15:45:58 -07001509 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1510 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1511
1512 flags0 = p0->flags;
1513
Damjan Marion213b5aa2017-07-13 21:19:27 +02001514 good_l4_checksum0 =
1515 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001516 len_diff0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001517
Dave Barachd7cb1b52016-12-09 09:52:16 -05001518 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1519 IP_PROTOCOL_UDP,
1520 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001521 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001522 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001523 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001524 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1525 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001526 /* Verify UDP length. */
1527 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1528 udp_len0 = clib_net_to_host_u16 (udp0->length);
1529 len_diff0 = ip_len0 - udp_len0;
1530 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001531
1532 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1534
1535 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001536 && !good_l4_checksum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001537 && !(flags0 &
1538 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539 {
1540 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1541 good_l4_checksum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001542 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001543 }
1544
1545 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1546
1547 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1548
Dave Barachd7cb1b52016-12-09 09:52:16 -05001549 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1550 IP6_ERROR_UDP_CHECKSUM);
1551 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1552 IP6_ERROR_ICMP_CHECKSUM);
1553 error0 =
1554 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001555
Dave Barachd7cb1b52016-12-09 09:52:16 -05001556 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001557 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1558 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001559 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001560 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301561 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001562 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563 }
1564
Dave Barachd7cb1b52016-12-09 09:52:16 -05001565 next0 =
1566 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001567
1568 p0->error = error_node->errors[error0];
1569
1570 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1571 to_next, n_left_to_next,
1572 pi0, next0);
1573 }
Dave Barach75fc8542016-10-11 16:16:02 -04001574
Ed Warnickecb9cada2015-12-08 15:45:58 -07001575 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1576 }
1577
1578 return frame->n_vectors;
1579}
1580
Dave Barachd7cb1b52016-12-09 09:52:16 -05001581/* *INDENT-OFF* */
1582VLIB_REGISTER_NODE (ip6_local_node, static) =
1583{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001584 .function = ip6_local,
1585 .name = "ip6-local",
1586 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001587 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001588 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001589 .next_nodes =
1590 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001591 [IP_LOCAL_NEXT_DROP] = "error-drop",
1592 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001593 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1594 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1595 },
1596};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001597/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598
Dave Barachd7cb1b52016-12-09 09:52:16 -05001599VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001600
Dave Barachd7cb1b52016-12-09 09:52:16 -05001601void
1602ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001604 vlib_main_t *vm = vlib_get_main ();
1605 ip6_main_t *im = &ip6_main;
1606 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001607
1608 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001609 lm->local_next_by_ip_protocol[protocol] =
1610 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611}
1612
Dave Barachd7cb1b52016-12-09 09:52:16 -05001613typedef enum
1614{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001616 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1618} ip6_discover_neighbor_next_t;
1619
Dave Barachd7cb1b52016-12-09 09:52:16 -05001620typedef enum
1621{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001622 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1623 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001624 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625} ip6_discover_neighbor_error_t;
1626
1627static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001628ip6_discover_neighbor_inline (vlib_main_t * vm,
1629 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001630 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001631{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001632 vnet_main_t *vnm = vnet_get_main ();
1633 ip6_main_t *im = &ip6_main;
1634 ip_lookup_main_t *lm = &im->lookup_main;
1635 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001636 uword n_left_from, n_left_to_next_drop;
1637 static f64 time_last_seed_change = -1e100;
1638 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001639 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001640 f64 time_now;
1641 int bogus_length;
1642
1643 if (node->flags & VLIB_NODE_FLAG_TRACE)
1644 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1645
1646 time_now = vlib_time_now (vm);
1647 if (time_now - time_last_seed_change > 1e-3)
1648 {
1649 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001650 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1651 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1653 hash_seeds[i] = r[i];
1654
1655 /* Mark all hash keys as been not-seen before. */
1656 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1657 hash_bitmap[i] = 0;
1658
1659 time_last_seed_change = time_now;
1660 }
1661
1662 from = vlib_frame_vector_args (frame);
1663 n_left_from = frame->n_vectors;
1664
1665 while (n_left_from > 0)
1666 {
1667 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1668 to_next_drop, n_left_to_next_drop);
1669
1670 while (n_left_from > 0 && n_left_to_next_drop > 0)
1671 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001672 vlib_buffer_t *p0;
1673 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001674 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1675 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001676 ip_adjacency_t *adj0;
1677 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001678 u32 next0;
1679
1680 pi0 = from[0];
1681
1682 p0 = vlib_get_buffer (vm, pi0);
1683
1684 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1685
1686 ip0 = vlib_buffer_get_current (p0);
1687
Neale Ranns107e7d42017-04-11 09:55:19 -07001688 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001689
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001690 if (!is_glean)
1691 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001692 ip0->dst_address.as_u64[0] =
1693 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1694 ip0->dst_address.as_u64[1] =
1695 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001696 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001697
Ed Warnickecb9cada2015-12-08 15:45:58 -07001698 a0 = hash_seeds[0];
1699 b0 = hash_seeds[1];
1700 c0 = hash_seeds[2];
1701
1702 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1703 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1704
1705 a0 ^= sw_if_index0;
1706 b0 ^= ip0->dst_address.as_u32[0];
1707 c0 ^= ip0->dst_address.as_u32[1];
1708
1709 hash_v3_mix32 (a0, b0, c0);
1710
1711 b0 ^= ip0->dst_address.as_u32[2];
1712 c0 ^= ip0->dst_address.as_u32[3];
1713
1714 hash_v3_finalize32 (a0, b0, c0);
1715
1716 c0 &= BITS (hash_bitmap) - 1;
1717 c0 = c0 / BITS (uword);
1718 m0 = (uword) 1 << (c0 % BITS (uword));
1719
1720 bm0 = hash_bitmap[c0];
1721 drop0 = (bm0 & m0) != 0;
1722
1723 /* Mark it as seen. */
1724 hash_bitmap[c0] = bm0 | m0;
1725
1726 from += 1;
1727 n_left_from -= 1;
1728 to_next_drop[0] = pi0;
1729 to_next_drop += 1;
1730 n_left_to_next_drop -= 1;
1731
Dave Barachd7cb1b52016-12-09 09:52:16 -05001732 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733
Dave Barachd7cb1b52016-12-09 09:52:16 -05001734 /* If the interface is link-down, drop the pkt */
1735 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1736 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001737
Dave Barach75fc8542016-10-11 16:16:02 -04001738 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001739 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1740 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001741 if (drop0)
1742 continue;
1743
Neale Rannsb80c5362016-10-08 13:03:40 +01001744 /*
1745 * the adj has been updated to a rewrite but the node the DPO that got
1746 * us here hasn't - yet. no big deal. we'll drop while we wait.
1747 */
1748 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1749 continue;
1750
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 {
1752 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001753 icmp6_neighbor_solicitation_header_t *h0;
1754 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001755
Dave Barach75fc8542016-10-11 16:16:02 -04001756 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001757 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001758
Dave Barach75fc8542016-10-11 16:16:02 -04001759 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 * Build ethernet header.
1761 * Choose source address based on destination lookup
1762 * adjacency.
1763 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001764 if (ip6_src_address_for_packet (lm,
1765 sw_if_index0,
1766 &h0->ip.src_address))
1767 {
1768 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001769 p0->error =
1770 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1771 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001772 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001773 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774
Dave Barach75fc8542016-10-11 16:16:02 -04001775 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001776 * Destination address is a solicited node multicast address.
1777 * We need to fill in
1778 * the low 24 bits with low 24 bits of target's address.
1779 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001780 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1781 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1782 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1783
1784 h0->neighbor.target_address = ip0->dst_address;
1785
Dave Barach75fc8542016-10-11 16:16:02 -04001786 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001787 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788
Dave Barachd7cb1b52016-12-09 09:52:16 -05001789 /* $$$$ appears we need this; why is the checksum non-zero? */
1790 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001791 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001792 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1793 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001794
Dave Barachd7cb1b52016-12-09 09:52:16 -05001795 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796
1797 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1798 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001799 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001800 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801
1802 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001803 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1805
John Lod1f5d042016-04-12 18:20:39 -04001806 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001807
1808 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1809 }
1810 }
1811
Dave Barach75fc8542016-10-11 16:16:02 -04001812 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001813 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 }
1815
1816 return frame->n_vectors;
1817}
1818
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001819static uword
1820ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001821 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001822{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001824}
1825
1826static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001828{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001829 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001830}
1831
Dave Barachd7cb1b52016-12-09 09:52:16 -05001832static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001834 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001835 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1836 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001837};
1838
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839/* *INDENT-OFF* */
1840VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1841{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842 .function = ip6_discover_neighbor,
1843 .name = "ip6-discover-neighbor",
1844 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001845 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1847 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001848 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849 .next_nodes =
1850 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001851 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001852 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001853 },
1854};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001855/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856
Dave Barachd7cb1b52016-12-09 09:52:16 -05001857/* *INDENT-OFF* */
1858VLIB_REGISTER_NODE (ip6_glean_node) =
1859{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001860 .function = ip6_glean,
1861 .name = "ip6-glean",
1862 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001863 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001864 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1865 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001866 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867 .next_nodes =
1868 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001869 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1870 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1871 },
1872};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001873/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001874
Ed Warnickecb9cada2015-12-08 15:45:58 -07001875clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001876ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1877{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001878 vnet_main_t *vnm = vnet_get_main ();
1879 ip6_main_t *im = &ip6_main;
1880 icmp6_neighbor_solicitation_header_t *h;
1881 ip6_address_t *src;
1882 ip_interface_address_t *ia;
1883 ip_adjacency_t *adj;
1884 vnet_hw_interface_t *hi;
1885 vnet_sw_interface_t *si;
1886 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001887 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001888 u32 bi = 0;
1889 int bogus_length;
1890
1891 si = vnet_get_sw_interface (vnm, sw_if_index);
1892
1893 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1894 {
1895 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001896 format_ip6_address, dst,
1897 format_vnet_sw_if_index_name, vnm,
1898 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001899 }
1900
Dave Barachd7cb1b52016-12-09 09:52:16 -05001901 src =
1902 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1903 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001904 {
1905 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001906 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001907 (0, "no matching interface address for destination %U (interface %U)",
1908 format_ip6_address, dst,
1909 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910 }
1911
Dave Barachd7cb1b52016-12-09 09:52:16 -05001912 h =
1913 vlib_packet_template_get_packet (vm,
1914 &im->discover_neighbor_packet_template,
1915 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001916
1917 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1918
1919 /* Destination address is a solicited node multicast address. We need to fill in
1920 the low 24 bits with low 24 bits of target's address. */
1921 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1922 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1923 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1924
1925 h->ip.src_address = src[0];
1926 h->neighbor.target_address = dst[0];
1927
Pavel Kotucek57808982017-08-02 08:20:19 +02001928 if (PREDICT_FALSE (!hi->hw_address))
1929 {
1930 return clib_error_return (0, "%U: interface %U do not support ip probe",
1931 format_ip6_address, dst,
1932 format_vnet_sw_if_index_name, vnm,
1933 sw_if_index);
1934 }
1935
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1937 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001938
Dave Barach75fc8542016-10-11 16:16:02 -04001939 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001940 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001941 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942
1943 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001944 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1945 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946
1947 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07001948 ip46_address_t nh = {
1949 .ip6 = *dst,
1950 };
1951
1952 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
1953 VNET_LINK_IP6, &nh, sw_if_index);
1954 adj = adj_get (ai);
1955
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1957 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1958
1959 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001960 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1961 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962 to_next[0] = bi;
1963 f->n_vectors = 1;
1964 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1965 }
1966
Neale Ranns7a272742017-05-30 02:08:14 -07001967 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968 return /* no error */ 0;
1969}
1970
Dave Barachd7cb1b52016-12-09 09:52:16 -05001971typedef enum
1972{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001973 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001974 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975} ip6_rewrite_next_t;
1976
1977always_inline uword
1978ip6_rewrite_inline (vlib_main_t * vm,
1979 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001980 vlib_frame_t * frame,
1981 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001982{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001983 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1984 u32 *from = vlib_frame_vector_args (frame);
1985 u32 n_left_from, n_left_to_next, *to_next, next_index;
1986 vlib_node_runtime_t *error_node =
1987 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001988
1989 n_left_from = frame->n_vectors;
1990 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02001991 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04001992
Ed Warnickecb9cada2015-12-08 15:45:58 -07001993 while (n_left_from > 0)
1994 {
1995 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1996
1997 while (n_left_from >= 4 && n_left_to_next >= 2)
1998 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001999 ip_adjacency_t *adj0, *adj1;
2000 vlib_buffer_t *p0, *p1;
2001 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002 u32 pi0, rw_len0, next0, error0, adj_index0;
2003 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002004 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04002005
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006 /* Prefetch next iteration. */
2007 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002008 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009
2010 p2 = vlib_get_buffer (vm, from[2]);
2011 p3 = vlib_get_buffer (vm, from[3]);
2012
2013 vlib_prefetch_buffer_header (p2, LOAD);
2014 vlib_prefetch_buffer_header (p3, LOAD);
2015
2016 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2017 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2018
2019 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2020 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2021 }
2022
2023 pi0 = to_next[0] = from[0];
2024 pi1 = to_next[1] = from[1];
2025
2026 from += 2;
2027 n_left_from -= 2;
2028 to_next += 2;
2029 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002030
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 p0 = vlib_get_buffer (vm, pi0);
2032 p1 = vlib_get_buffer (vm, pi1);
2033
Neale Rannsf06aea52016-11-29 06:51:37 -08002034 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2035 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002036
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037 ip0 = vlib_buffer_get_current (p0);
2038 ip1 = vlib_buffer_get_current (p1);
2039
2040 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002041 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002042
Damjan Marion213b5aa2017-07-13 21:19:27 +02002043 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002045 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046
2047 /* Input node should have reject packets with hop limit 0. */
2048 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002049
2050 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002051
2052 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053
Dave Barachd7cb1b52016-12-09 09:52:16 -05002054 /*
2055 * If the hop count drops below 1 when forwarding, generate
2056 * an ICMP response.
2057 */
2058 if (PREDICT_FALSE (hop_limit0 <= 0))
2059 {
2060 error0 = IP6_ERROR_TIME_EXPIRED;
2061 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2062 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2063 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2064 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2065 0);
2066 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002067 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002068 else
2069 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002070 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002071 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002072 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002073 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002074 i32 hop_limit1 = ip1->hop_limit;
2075
2076 /* Input node should have reject packets with hop limit 0. */
2077 ASSERT (ip1->hop_limit > 0);
2078
2079 hop_limit1 -= 1;
2080
2081 ip1->hop_limit = hop_limit1;
2082
Dave Barachd7cb1b52016-12-09 09:52:16 -05002083 /*
2084 * If the hop count drops below 1 when forwarding, generate
2085 * an ICMP response.
2086 */
2087 if (PREDICT_FALSE (hop_limit1 <= 0))
2088 {
2089 error1 = IP6_ERROR_TIME_EXPIRED;
2090 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2091 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2092 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2093 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2094 0);
2095 }
2096 }
2097 else
2098 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002099 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002100 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002101 adj0 = adj_get (adj_index0);
2102 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104 rw_len0 = adj0[0].rewrite_header.data_bytes;
2105 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002106 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2107 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002108
Neale Ranns9c6a6132017-02-21 05:33:14 -08002109 if (do_counters)
2110 {
2111 vlib_increment_combined_counter
2112 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002113 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002114 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2115 vlib_increment_combined_counter
2116 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002117 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002118 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2119 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002120
2121 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002122 error0 =
2123 (vlib_buffer_length_in_chain (vm, p0) >
2124 adj0[0].
2125 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2126 error0);
2127 error1 =
2128 (vlib_buffer_length_in_chain (vm, p1) >
2129 adj1[0].
2130 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2131 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
Dave Barachd7cb1b52016-12-09 09:52:16 -05002133 /* Don't adjust the buffer for hop count issue; icmp-error node
2134 * wants to see the IP headerr */
2135 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2136 {
2137 p0->current_data -= rw_len0;
2138 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002139
Dave Barachd7cb1b52016-12-09 09:52:16 -05002140 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2141 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2142 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002143
Neale Rannsb069a692017-03-15 12:34:25 -04002144 if (PREDICT_FALSE
2145 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2146 vnet_feature_arc_start (lm->output_feature_arc_index,
2147 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002148 }
2149 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2150 {
2151 p1->current_data -= rw_len1;
2152 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002153
Dave Barachd7cb1b52016-12-09 09:52:16 -05002154 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2155 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2156 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002157
Neale Rannsb069a692017-03-15 12:34:25 -04002158 if (PREDICT_FALSE
2159 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2160 vnet_feature_arc_start (lm->output_feature_arc_index,
2161 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002162 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163
2164 /* Guess we are only writing on simple Ethernet header. */
2165 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002166 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002167
Neale Ranns5e575b12016-10-03 09:40:25 +01002168 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002169 {
2170 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2171 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2172 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002173 if (is_mcast)
2174 {
2175 /*
2176 * copy bytes from the IP address into the MAC rewrite
2177 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002178 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2179 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002180 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002181
Ed Warnickecb9cada2015-12-08 15:45:58 -07002182 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2183 to_next, n_left_to_next,
2184 pi0, pi1, next0, next1);
2185 }
2186
2187 while (n_left_from > 0 && n_left_to_next > 0)
2188 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002189 ip_adjacency_t *adj0;
2190 vlib_buffer_t *p0;
2191 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192 u32 pi0, rw_len0;
2193 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002194 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002195
Ed Warnickecb9cada2015-12-08 15:45:58 -07002196 pi0 = to_next[0] = from[0];
2197
2198 p0 = vlib_get_buffer (vm, pi0);
2199
Neale Rannsf06aea52016-11-29 06:51:37 -08002200 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002201
Neale Ranns107e7d42017-04-11 09:55:19 -07002202 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002203
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204 ip0 = vlib_buffer_get_current (p0);
2205
2206 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002207 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002208
2209 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002210 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002211 {
2212 i32 hop_limit0 = ip0->hop_limit;
2213
2214 ASSERT (ip0->hop_limit > 0);
2215
2216 hop_limit0 -= 1;
2217
2218 ip0->hop_limit = hop_limit0;
2219
Dave Barachd7cb1b52016-12-09 09:52:16 -05002220 if (PREDICT_FALSE (hop_limit0 <= 0))
2221 {
2222 /*
2223 * If the hop count drops below 1 when forwarding, generate
2224 * an ICMP response.
2225 */
2226 error0 = IP6_ERROR_TIME_EXPIRED;
2227 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2228 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2229 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2230 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2231 0);
2232 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002234 else
2235 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002236 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002237 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002238
Ed Warnickecb9cada2015-12-08 15:45:58 -07002239 /* Guess we are only writing on simple Ethernet header. */
2240 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002241
Ed Warnickecb9cada2015-12-08 15:45:58 -07002242 /* Update packet buffer attributes/set output interface. */
2243 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002245
Neale Ranns9c6a6132017-02-21 05:33:14 -08002246 if (do_counters)
2247 {
2248 vlib_increment_combined_counter
2249 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002250 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002251 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2252 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002253
2254 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002255 error0 =
2256 (vlib_buffer_length_in_chain (vm, p0) >
2257 adj0[0].
2258 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2259 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260
Dave Barachd7cb1b52016-12-09 09:52:16 -05002261 /* Don't adjust the buffer for hop count issue; icmp-error node
2262 * wants to see the IP headerr */
2263 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2264 {
Chris Luke816f3e12016-06-14 16:24:47 -04002265 p0->current_data -= rw_len0;
2266 p0->current_length += rw_len0;
2267
Dave Barachd7cb1b52016-12-09 09:52:16 -05002268 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002269
Dave Barachd7cb1b52016-12-09 09:52:16 -05002270 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2271 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002272
Neale Rannsb069a692017-03-15 12:34:25 -04002273 if (PREDICT_FALSE
2274 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2275 vnet_feature_arc_start (lm->output_feature_arc_index,
2276 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002277 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278
Neale Ranns5e575b12016-10-03 09:40:25 +01002279 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002280 {
2281 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2282 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002283 if (is_mcast)
2284 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002285 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002286 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002287
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 p0->error = error_node->errors[error0];
2289
2290 from += 1;
2291 n_left_from -= 1;
2292 to_next += 1;
2293 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002294
Ed Warnickecb9cada2015-12-08 15:45:58 -07002295 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2296 to_next, n_left_to_next,
2297 pi0, next0);
2298 }
2299
2300 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2301 }
2302
2303 /* Need to do trace after rewrites to pick up new packet data. */
2304 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002305 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306
2307 return frame->n_vectors;
2308}
2309
2310static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002311ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002314 if (adj_are_counters_enabled ())
2315 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2316 else
2317 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002318}
2319
2320static uword
2321ip6_rewrite_mcast (vlib_main_t * vm,
2322 vlib_node_runtime_t * node, vlib_frame_t * frame)
2323{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002324 if (adj_are_counters_enabled ())
2325 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2326 else
2327 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328}
2329
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002330static uword
2331ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002333{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002334 if (adj_are_counters_enabled ())
2335 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2336 else
2337 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002338}
2339
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002340static uword
2341ip6_mcast_midchain (vlib_main_t * vm,
2342 vlib_node_runtime_t * node, vlib_frame_t * frame)
2343{
2344 if (adj_are_counters_enabled ())
2345 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2346 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002347 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002348}
2349
Dave Barachd7cb1b52016-12-09 09:52:16 -05002350/* *INDENT-OFF* */
2351VLIB_REGISTER_NODE (ip6_midchain_node) =
2352{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002353 .function = ip6_midchain,
2354 .name = "ip6-midchain",
2355 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002356 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002357 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002358 };
2359/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002360
Dave Barachd7cb1b52016-12-09 09:52:16 -05002361VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002362
Dave Barachd7cb1b52016-12-09 09:52:16 -05002363/* *INDENT-OFF* */
2364VLIB_REGISTER_NODE (ip6_rewrite_node) =
2365{
Neale Rannsf06aea52016-11-29 06:51:37 -08002366 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002367 .name = "ip6-rewrite",
2368 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002369 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002370 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002371 .next_nodes =
2372 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002373 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002374 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002375 },
2376};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002377/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378
Neale Rannsf06aea52016-11-29 06:51:37 -08002379VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002380
Neale Ranns32e1c012016-11-22 17:07:28 +00002381/* *INDENT-OFF* */
2382VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2383{
2384 .function = ip6_rewrite_mcast,
2385 .name = "ip6-rewrite-mcast",
2386 .vector_size = sizeof (u32),
2387 .format_trace = format_ip6_rewrite_trace,
2388 .sibling_of = "ip6-rewrite",
2389};
2390/* *INDENT-ON* */
2391
2392VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2393
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002394/* *INDENT-OFF* */
2395VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2396{
2397 .function = ip6_mcast_midchain,
2398 .name = "ip6-mcast-midchain",
2399 .vector_size = sizeof (u32),
2400 .format_trace = format_ip6_rewrite_trace,
2401 .sibling_of = "ip6-rewrite",
2402};
2403/* *INDENT-ON* */
2404
2405VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2406
Ole Troan944f5482016-05-24 11:56:58 +02002407/*
2408 * Hop-by-Hop handling
2409 */
Ole Troan944f5482016-05-24 11:56:58 +02002410ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2411
2412#define foreach_ip6_hop_by_hop_error \
2413_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2414_(FORMAT, "incorrectly formatted hop-by-hop options") \
2415_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2416
Neale Ranns32e1c012016-11-22 17:07:28 +00002417/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002418typedef enum
2419{
Ole Troan944f5482016-05-24 11:56:58 +02002420#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2421 foreach_ip6_hop_by_hop_error
2422#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002423 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002424} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002425/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002426
2427/*
2428 * Primary h-b-h handler trace support
2429 * We work pretty hard on the problem for obvious reasons
2430 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002431typedef struct
2432{
Ole Troan944f5482016-05-24 11:56:58 +02002433 u32 next_index;
2434 u32 trace_len;
2435 u8 option_data[256];
2436} ip6_hop_by_hop_trace_t;
2437
2438vlib_node_registration_t ip6_hop_by_hop_node;
2439
Dave Barachd7cb1b52016-12-09 09:52:16 -05002440static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002441#define _(sym,string) string,
2442 foreach_ip6_hop_by_hop_error
2443#undef _
2444};
2445
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302446u8 *
2447format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2448{
2449 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2450 int total_len = va_arg (*args, int);
2451 ip6_hop_by_hop_option_t *opt0, *limit0;
2452 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2453 u8 type0;
2454
2455 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2456 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2457
2458 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2459 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2460
2461 while (opt0 < limit0)
2462 {
2463 type0 = opt0->type;
2464 switch (type0)
2465 {
2466 case 0: /* Pad, just stop */
2467 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2468 break;
2469
2470 default:
2471 if (hm->trace[type0])
2472 {
2473 s = (*hm->trace[type0]) (s, opt0);
2474 }
2475 else
2476 {
2477 s =
2478 format (s, "\n unrecognized option %d length %d", type0,
2479 opt0->length);
2480 }
2481 opt0 =
2482 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2483 sizeof (ip6_hop_by_hop_option_t));
2484 break;
2485 }
2486 }
2487 return s;
2488}
2489
Ole Troan944f5482016-05-24 11:56:58 +02002490static u8 *
2491format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2492{
2493 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2494 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002495 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002496 ip6_hop_by_hop_header_t *hbh0;
2497 ip6_hop_by_hop_option_t *opt0, *limit0;
2498 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2499
2500 u8 type0;
2501
Dave Barachd7cb1b52016-12-09 09:52:16 -05002502 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002503
2504 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002506
Dave Barachd7cb1b52016-12-09 09:52:16 -05002507 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2508 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002509
Dave Barachd7cb1b52016-12-09 09:52:16 -05002510 while (opt0 < limit0)
2511 {
2512 type0 = opt0->type;
2513 switch (type0)
2514 {
2515 case 0: /* Pad, just stop */
2516 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2517 break;
Ole Troan944f5482016-05-24 11:56:58 +02002518
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 default:
2520 if (hm->trace[type0])
2521 {
2522 s = (*hm->trace[type0]) (s, opt0);
2523 }
2524 else
2525 {
2526 s =
2527 format (s, "\n unrecognized option %d length %d", type0,
2528 opt0->length);
2529 }
2530 opt0 =
2531 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2532 sizeof (ip6_hop_by_hop_option_t));
2533 break;
2534 }
Ole Troan944f5482016-05-24 11:56:58 +02002535 }
Ole Troan944f5482016-05-24 11:56:58 +02002536 return s;
2537}
2538
Dave Barachd7cb1b52016-12-09 09:52:16 -05002539always_inline u8
2540ip6_scan_hbh_options (vlib_buffer_t * b0,
2541 ip6_header_t * ip0,
2542 ip6_hop_by_hop_header_t * hbh0,
2543 ip6_hop_by_hop_option_t * opt0,
2544 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002545{
2546 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2547 u8 type0;
2548 u8 error0 = 0;
2549
2550 while (opt0 < limit0)
2551 {
2552 type0 = opt0->type;
2553 switch (type0)
2554 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002555 case 0: /* Pad1 */
2556 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002557 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002558 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002559 break;
2560 default:
2561 if (hm->options[type0])
2562 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2564 {
Shwethaa91cbe62016-08-08 15:51:04 +01002565 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002566 return (error0);
2567 }
Shwethaa91cbe62016-08-08 15:51:04 +01002568 }
2569 else
2570 {
2571 /* Unrecognized mandatory option, check the two high order bits */
2572 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2573 {
2574 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2575 break;
2576 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2577 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2578 *next0 = IP_LOOKUP_NEXT_DROP;
2579 break;
2580 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2581 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2582 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002583 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2584 ICMP6_parameter_problem_unrecognized_option,
2585 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002586 break;
2587 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2588 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002589 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002590 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002591 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2592 icmp6_error_set_vnet_buffer (b0,
2593 ICMP6_parameter_problem,
2594 ICMP6_parameter_problem_unrecognized_option,
2595 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002596 }
2597 else
2598 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002599 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002600 }
2601 break;
2602 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002603 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002604 }
2605 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002606 opt0 =
2607 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2608 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002609 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002610 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002611}
2612
Ole Troan944f5482016-05-24 11:56:58 +02002613/*
2614 * Process the Hop-by-Hop Options header
2615 */
2616static uword
2617ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002618 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002619{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 vlib_node_runtime_t *error_node =
2621 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002622 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2623 u32 n_left_from, *from, *to_next;
2624 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002625
2626 from = vlib_frame_vector_args (frame);
2627 n_left_from = frame->n_vectors;
2628 next_index = node->cached_next_index;
2629
Dave Barachd7cb1b52016-12-09 09:52:16 -05002630 while (n_left_from > 0)
2631 {
2632 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002633
Dave Barachd7cb1b52016-12-09 09:52:16 -05002634 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002635
Dave Barachd7cb1b52016-12-09 09:52:16 -05002636 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002637 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002638 u32 bi0, bi1;
2639 vlib_buffer_t *b0, *b1;
2640 u32 next0, next1;
2641 ip6_header_t *ip0, *ip1;
2642 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2643 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2644 u8 error0 = 0, error1 = 0;
2645
2646 /* Prefetch next iteration. */
2647 {
2648 vlib_buffer_t *p2, *p3;
2649
2650 p2 = vlib_get_buffer (vm, from[2]);
2651 p3 = vlib_get_buffer (vm, from[3]);
2652
2653 vlib_prefetch_buffer_header (p2, LOAD);
2654 vlib_prefetch_buffer_header (p3, LOAD);
2655
2656 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2657 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002658 }
2659
Dave Barachd7cb1b52016-12-09 09:52:16 -05002660 /* Speculatively enqueue b0, b1 to the current next frame */
2661 to_next[0] = bi0 = from[0];
2662 to_next[1] = bi1 = from[1];
2663 from += 2;
2664 to_next += 2;
2665 n_left_from -= 2;
2666 n_left_to_next -= 2;
2667
2668 b0 = vlib_get_buffer (vm, bi0);
2669 b1 = vlib_get_buffer (vm, bi1);
2670
2671 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2672 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002673 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002674 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002675 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002676
2677 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2678 next0 = adj0->lookup_next_index;
2679 next1 = adj1->lookup_next_index;
2680
2681 ip0 = vlib_buffer_get_current (b0);
2682 ip1 = vlib_buffer_get_current (b1);
2683 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2684 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2685 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2686 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2687 limit0 =
2688 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2689 ((hbh0->length + 1) << 3));
2690 limit1 =
2691 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2692 ((hbh1->length + 1) << 3));
2693
2694 /*
2695 * Basic validity checks
2696 */
2697 if ((hbh0->length + 1) << 3 >
2698 clib_net_to_host_u16 (ip0->payload_length))
2699 {
2700 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2701 next0 = IP_LOOKUP_NEXT_DROP;
2702 goto outdual;
2703 }
2704 /* Scan the set of h-b-h options, process ones that we understand */
2705 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2706
2707 if ((hbh1->length + 1) << 3 >
2708 clib_net_to_host_u16 (ip1->payload_length))
2709 {
2710 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2711 next1 = IP_LOOKUP_NEXT_DROP;
2712 goto outdual;
2713 }
2714 /* Scan the set of h-b-h options, process ones that we understand */
2715 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2716
2717 outdual:
2718 /* Has the classifier flagged this buffer for special treatment? */
2719 if (PREDICT_FALSE
2720 ((error0 == 0)
2721 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2722 next0 = hm->next_override;
2723
2724 /* Has the classifier flagged this buffer for special treatment? */
2725 if (PREDICT_FALSE
2726 ((error1 == 0)
2727 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2728 next1 = hm->next_override;
2729
2730 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2731 {
2732 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2733 {
2734 ip6_hop_by_hop_trace_t *t =
2735 vlib_add_trace (vm, node, b0, sizeof (*t));
2736 u32 trace_len = (hbh0->length + 1) << 3;
2737 t->next_index = next0;
2738 /* Capture the h-b-h option verbatim */
2739 trace_len =
2740 trace_len <
2741 ARRAY_LEN (t->option_data) ? trace_len :
2742 ARRAY_LEN (t->option_data);
2743 t->trace_len = trace_len;
2744 clib_memcpy (t->option_data, hbh0, trace_len);
2745 }
2746 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2747 {
2748 ip6_hop_by_hop_trace_t *t =
2749 vlib_add_trace (vm, node, b1, sizeof (*t));
2750 u32 trace_len = (hbh1->length + 1) << 3;
2751 t->next_index = next1;
2752 /* Capture the h-b-h option verbatim */
2753 trace_len =
2754 trace_len <
2755 ARRAY_LEN (t->option_data) ? trace_len :
2756 ARRAY_LEN (t->option_data);
2757 t->trace_len = trace_len;
2758 clib_memcpy (t->option_data, hbh1, trace_len);
2759 }
2760
2761 }
2762
2763 b0->error = error_node->errors[error0];
2764 b1->error = error_node->errors[error1];
2765
2766 /* verify speculative enqueue, maybe switch current next frame */
2767 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2768 n_left_to_next, bi0, bi1, next0,
2769 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002770 }
2771
Dave Barachd7cb1b52016-12-09 09:52:16 -05002772 while (n_left_from > 0 && n_left_to_next > 0)
2773 {
2774 u32 bi0;
2775 vlib_buffer_t *b0;
2776 u32 next0;
2777 ip6_header_t *ip0;
2778 ip6_hop_by_hop_header_t *hbh0;
2779 ip6_hop_by_hop_option_t *opt0, *limit0;
2780 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002781
Dave Barachd7cb1b52016-12-09 09:52:16 -05002782 /* Speculatively enqueue b0 to the current next frame */
2783 bi0 = from[0];
2784 to_next[0] = bi0;
2785 from += 1;
2786 to_next += 1;
2787 n_left_from -= 1;
2788 n_left_to_next -= 1;
2789
2790 b0 = vlib_get_buffer (vm, bi0);
2791 /*
2792 * Default use the next_index from the adjacency.
2793 * A HBH option rarely redirects to a different node
2794 */
2795 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002796 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002797 next0 = adj0->lookup_next_index;
2798
2799 ip0 = vlib_buffer_get_current (b0);
2800 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2801 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2802 limit0 =
2803 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2804 ((hbh0->length + 1) << 3));
2805
2806 /*
2807 * Basic validity checks
2808 */
2809 if ((hbh0->length + 1) << 3 >
2810 clib_net_to_host_u16 (ip0->payload_length))
2811 {
2812 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2813 next0 = IP_LOOKUP_NEXT_DROP;
2814 goto out0;
2815 }
2816
2817 /* Scan the set of h-b-h options, process ones that we understand */
2818 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2819
2820 out0:
2821 /* Has the classifier flagged this buffer for special treatment? */
2822 if (PREDICT_FALSE
2823 ((error0 == 0)
2824 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2825 next0 = hm->next_override;
2826
2827 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2828 {
2829 ip6_hop_by_hop_trace_t *t =
2830 vlib_add_trace (vm, node, b0, sizeof (*t));
2831 u32 trace_len = (hbh0->length + 1) << 3;
2832 t->next_index = next0;
2833 /* Capture the h-b-h option verbatim */
2834 trace_len =
2835 trace_len <
2836 ARRAY_LEN (t->option_data) ? trace_len :
2837 ARRAY_LEN (t->option_data);
2838 t->trace_len = trace_len;
2839 clib_memcpy (t->option_data, hbh0, trace_len);
2840 }
2841
2842 b0->error = error_node->errors[error0];
2843
2844 /* verify speculative enqueue, maybe switch current next frame */
2845 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2846 n_left_to_next, bi0, next0);
2847 }
2848 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002849 }
Ole Troan944f5482016-05-24 11:56:58 +02002850 return frame->n_vectors;
2851}
2852
Dave Barachd7cb1b52016-12-09 09:52:16 -05002853/* *INDENT-OFF* */
2854VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2855{
Ole Troan944f5482016-05-24 11:56:58 +02002856 .function = ip6_hop_by_hop,
2857 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002858 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002859 .vector_size = sizeof (u32),
2860 .format_trace = format_ip6_hop_by_hop_trace,
2861 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002863 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002864 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002865};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002866/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002867
Dave Barach5331c722016-08-17 11:54:30 -04002868VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002869
2870static clib_error_t *
2871ip6_hop_by_hop_init (vlib_main_t * vm)
2872{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002873 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2874 memset (hm->options, 0, sizeof (hm->options));
2875 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002876 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002877 return (0);
2878}
2879
2880VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2881
Dave Barachd7cb1b52016-12-09 09:52:16 -05002882void
2883ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002884{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002885 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002886
2887 hm->next_override = next;
2888}
2889
Ole Troan944f5482016-05-24 11:56:58 +02002890int
2891ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002892 int options (vlib_buffer_t * b, ip6_header_t * ip,
2893 ip6_hop_by_hop_option_t * opt),
2894 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002895{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002896 ip6_main_t *im = &ip6_main;
2897 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002898
2899 ASSERT (option < ARRAY_LEN (hm->options));
2900
2901 /* Already registered */
2902 if (hm->options[option])
2903 return (-1);
2904
2905 hm->options[option] = options;
2906 hm->trace[option] = trace;
2907
2908 /* Set global variable */
2909 im->hbh_enabled = 1;
2910
2911 return (0);
2912}
2913
2914int
2915ip6_hbh_unregister_option (u8 option)
2916{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 ip6_main_t *im = &ip6_main;
2918 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002919
2920 ASSERT (option < ARRAY_LEN (hm->options));
2921
2922 /* Not registered */
2923 if (!hm->options[option])
2924 return (-1);
2925
2926 hm->options[option] = NULL;
2927 hm->trace[option] = NULL;
2928
2929 /* Disable global knob if this was the last option configured */
2930 int i;
2931 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002932 for (i = 0; i < 256; i++)
2933 {
2934 if (hm->options[option])
2935 {
2936 found = true;
2937 break;
2938 }
Ole Troan944f5482016-05-24 11:56:58 +02002939 }
Ole Troan944f5482016-05-24 11:56:58 +02002940 if (!found)
2941 im->hbh_enabled = 0;
2942
2943 return (0);
2944}
2945
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946/* Global IP6 main. */
2947ip6_main_t ip6_main;
2948
2949static clib_error_t *
2950ip6_lookup_init (vlib_main_t * vm)
2951{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952 ip6_main_t *im = &ip6_main;
2953 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954 uword i;
2955
Damjan Marion8b3191e2016-11-09 19:54:20 +01002956 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2957 return error;
2958
Ed Warnickecb9cada2015-12-08 15:45:58 -07002959 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2960 {
2961 u32 j, i0, i1;
2962
2963 i0 = i / 32;
2964 i1 = i % 32;
2965
2966 for (j = 0; j < i0; j++)
2967 im->fib_masks[i].as_u32[j] = ~0;
2968
2969 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002970 im->fib_masks[i].as_u32[i0] =
2971 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002972 }
2973
2974 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2975
2976 if (im->lookup_table_nbuckets == 0)
2977 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2978
Dave Barachd7cb1b52016-12-09 09:52:16 -05002979 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980
2981 if (im->lookup_table_size == 0)
2982 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002983
Dave Barachd7cb1b52016-12-09 09:52:16 -05002984 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2985 "ip6 FIB fwding table",
2986 im->lookup_table_nbuckets, im->lookup_table_size);
2987 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2988 "ip6 FIB non-fwding table",
2989 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002990
Ed Warnickecb9cada2015-12-08 15:45:58 -07002991 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002992 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002993 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002994
2995 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002996 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997 pn = pg_get_node (ip6_lookup_node.index);
2998 pn->unformat_edit = unformat_pg_ip6_header;
2999 }
3000
Ole Troan944f5482016-05-24 11:56:58 +02003001 /* Unless explicitly configured, don't process HBH options */
3002 im->hbh_enabled = 0;
3003
Ed Warnickecb9cada2015-12-08 15:45:58 -07003004 {
3005 icmp6_neighbor_solicitation_header_t p;
3006
3007 memset (&p, 0, sizeof (p));
3008
Dave Barachd7cb1b52016-12-09 09:52:16 -05003009 p.ip.ip_version_traffic_class_and_flow_label =
3010 clib_host_to_net_u32 (0x6 << 28);
3011 p.ip.payload_length =
3012 clib_host_to_net_u16 (sizeof (p) -
3013 STRUCT_OFFSET_OF
3014 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003015 p.ip.protocol = IP_PROTOCOL_ICMP6;
3016 p.ip.hop_limit = 255;
3017 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3018
3019 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3020
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021 p.link_layer_option.header.type =
3022 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3023 p.link_layer_option.header.n_data_u64s =
3024 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025
3026 vlib_packet_template_init (vm,
3027 &im->discover_neighbor_packet_template,
3028 &p, sizeof (p),
3029 /* alloc chunk size */ 8,
3030 "ip6 neighbor discovery");
3031 }
3032
Dave Barach203c6322016-06-26 10:29:03 -04003033 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003034}
3035
3036VLIB_INIT_FUNCTION (ip6_lookup_init);
3037
3038static clib_error_t *
3039add_del_ip6_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003040 unformat_input_t * input,
3041 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003042{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003043 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08003044 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003045 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003046 u32 sw_if_index, table_id;
3047
3048 sw_if_index = ~0;
3049
Dave Barachd7cb1b52016-12-09 09:52:16 -05003050 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07003051 {
3052 error = clib_error_return (0, "unknown interface `%U'",
3053 format_unformat_error, input);
3054 goto done;
3055 }
3056
3057 if (unformat (input, "%d", &table_id))
3058 ;
3059 else
3060 {
3061 error = clib_error_return (0, "expected table id `%U'",
3062 format_unformat_error, input);
3063 goto done;
3064 }
3065
Neale Ranns4008ac92017-02-13 23:20:04 -08003066 /*
3067 * If the interface already has in IP address, then a change int
3068 * VRF is not allowed. The IP address applied must first be removed.
3069 * We do not do that automatically here, since VPP has no knowledge
3070 * of whether thoses subnets are valid in the destination VRF.
3071 */
3072 /* *INDENT-OFF* */
3073 foreach_ip_interface_address (&ip6_main.lookup_main,
3074 ia, sw_if_index,
3075 1 /* honor unnumbered */,
3076 ({
3077 ip4_address_t * a;
3078
3079 a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
3080 error = clib_error_return (0, "interface %U has address %U",
3081 format_vnet_sw_if_index_name, vnm,
3082 sw_if_index,
3083 format_ip6_address, a);
3084 goto done;
3085 }));
3086 /* *INDENT-ON* */
3087
Ed Warnickecb9cada2015-12-08 15:45:58 -07003088 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089 u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3090 table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003092 vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
3093 ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00003094
3095 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3096 table_id);
3097
3098 vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
3099 ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003100 }
3101
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003102
Dave Barachd7cb1b52016-12-09 09:52:16 -05003103done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003104 return error;
3105}
3106
Billy McFall0683c9c2016-10-13 08:27:31 -04003107/*?
3108 * Place the indicated interface into the supplied IPv6 FIB table (also known
3109 * as a VRF). If the FIB table does not exist, this command creates it. To
3110 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3111 * FIB table will only be displayed if a route has been added to the table, or
3112 * an IP Address is assigned to an interface in the table (which adds a route
3113 * automatically).
3114 *
Neale Ranns4008ac92017-02-13 23:20:04 -08003115 * @note IP addresses added after setting the interface IP table are added to
3116 * the indicated FIB table. If an IP address is added prior to changing the
3117 * table then this is an error. The control plane must remove these addresses
3118 * first and then change the table. VPP will not automatically move the
3119 * addresses from the old to the new table as it does not know the validity
3120 * of such a change.
Billy McFall0683c9c2016-10-13 08:27:31 -04003121 *
3122 * @cliexpar
3123 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3124 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3125 ?*/
3126/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003127VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3128{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003129 .path = "set interface ip6 table",
3130 .function = add_del_ip6_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04003131 .short_help = "set interface ip6 table <interface> <table-id>"
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132};
Billy McFall0683c9c2016-10-13 08:27:31 -04003133/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134
Dave Barach75fc8542016-10-11 16:16:02 -04003135void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003136ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3137 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138{
3139 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3140 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003141 ip->as_u8[8] = mac[0] ^ (1 << 1);
3142 ip->as_u8[9] = mac[1];
3143 ip->as_u8[10] = mac[2];
3144 ip->as_u8[11] = 0xFF;
3145 ip->as_u8[12] = 0xFE;
3146 ip->as_u8[13] = mac[3];
3147 ip->as_u8[14] = mac[4];
3148 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149}
3150
Dave Barach75fc8542016-10-11 16:16:02 -04003151void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003152ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3153 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003154{
3155 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003156 mac[0] = ip->as_u8[8] ^ (1 << 1);
3157 mac[1] = ip->as_u8[9];
3158 mac[2] = ip->as_u8[10];
3159 mac[3] = ip->as_u8[13];
3160 mac[4] = ip->as_u8[14];
3161 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003162}
3163
Dave Barach75fc8542016-10-11 16:16:02 -04003164static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003165test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003166 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167{
3168 u8 mac[6];
3169 ip6_address_t _a, *a = &_a;
3170
3171 if (unformat (input, "%U", unformat_ethernet_address, mac))
3172 {
3173 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003174 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3176 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003177 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003178 }
Dave Barach75fc8542016-10-11 16:16:02 -04003179
Ed Warnickecb9cada2015-12-08 15:45:58 -07003180 return 0;
3181}
3182
Billy McFall0683c9c2016-10-13 08:27:31 -04003183/*?
3184 * This command converts the given MAC Address into an IPv6 link-local
3185 * address.
3186 *
3187 * @cliexpar
3188 * Example of how to create an IPv6 link-local address:
3189 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3190 * Link local address: fe80::14d9:e0ff:fe91:7986
3191 * Original MAC address: 16:d9:e0:91:79:86
3192 * @cliexend
3193?*/
3194/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003195VLIB_CLI_COMMAND (test_link_command, static) =
3196{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003197 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003198 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003199 .short_help = "test ip6 link <mac-address>",
3200};
Billy McFall0683c9c2016-10-13 08:27:31 -04003201/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003202
Dave Barachd7cb1b52016-12-09 09:52:16 -05003203int
3204vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003205{
Neale Ranns107e7d42017-04-11 09:55:19 -07003206 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003207
Neale Ranns107e7d42017-04-11 09:55:19 -07003208 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003209
Neale Ranns107e7d42017-04-11 09:55:19 -07003210 if (~0 == fib_index)
3211 return VNET_API_ERROR_NO_SUCH_FIB;
3212
Neale Ranns227038a2017-04-21 01:07:59 -07003213 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3214 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003215
Neale Ranns227038a2017-04-21 01:07:59 -07003216 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217}
3218
3219static clib_error_t *
3220set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003221 unformat_input_t * input,
3222 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003223{
3224 int matched = 0;
3225 u32 table_id = 0;
3226 u32 flow_hash_config = 0;
3227 int rv;
3228
Dave Barachd7cb1b52016-12-09 09:52:16 -05003229 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3230 {
3231 if (unformat (input, "table %d", &table_id))
3232 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003233#define _(a,v) \
3234 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003235 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003236#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003237 else
3238 break;
3239 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003240
3241 if (matched == 0)
3242 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003243 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003244
Ed Warnickecb9cada2015-12-08 15:45:58 -07003245 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3246 switch (rv)
3247 {
Neale Ranns227038a2017-04-21 01:07:59 -07003248 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003249 break;
3250
3251 case -1:
3252 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003253
Ed Warnickecb9cada2015-12-08 15:45:58 -07003254 default:
3255 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3256 break;
3257 }
Dave Barach75fc8542016-10-11 16:16:02 -04003258
Ed Warnickecb9cada2015-12-08 15:45:58 -07003259 return 0;
3260}
3261
Billy McFall0683c9c2016-10-13 08:27:31 -04003262/*?
3263 * Configure the set of IPv6 fields used by the flow hash.
3264 *
3265 * @cliexpar
3266 * @parblock
3267 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003268 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3269 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003270 * Example of display the configured flow hash:
3271 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003272 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3273 * @::/0
3274 * unicast-ip6-chain
3275 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3276 * [0] [@0]: dpo-drop ip6
3277 * fe80::/10
3278 * unicast-ip6-chain
3279 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3280 * [0] [@2]: dpo-receive
3281 * ff02::1/128
3282 * unicast-ip6-chain
3283 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3284 * [0] [@2]: dpo-receive
3285 * ff02::2/128
3286 * unicast-ip6-chain
3287 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3288 * [0] [@2]: dpo-receive
3289 * ff02::16/128
3290 * unicast-ip6-chain
3291 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3292 * [0] [@2]: dpo-receive
3293 * ff02::1:ff00:0/104
3294 * unicast-ip6-chain
3295 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3296 * [0] [@2]: dpo-receive
3297 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3298 * @::/0
3299 * unicast-ip6-chain
3300 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3301 * [0] [@0]: dpo-drop ip6
3302 * @::a:1:1:0:4/126
3303 * unicast-ip6-chain
3304 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3305 * [0] [@4]: ipv6-glean: af_packet0
3306 * @::a:1:1:0:7/128
3307 * unicast-ip6-chain
3308 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3309 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3310 * fe80::/10
3311 * unicast-ip6-chain
3312 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3313 * [0] [@2]: dpo-receive
3314 * fe80::fe:3eff:fe3e:9222/128
3315 * unicast-ip6-chain
3316 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3317 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3318 * ff02::1/128
3319 * unicast-ip6-chain
3320 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3321 * [0] [@2]: dpo-receive
3322 * ff02::2/128
3323 * unicast-ip6-chain
3324 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3325 * [0] [@2]: dpo-receive
3326 * ff02::16/128
3327 * unicast-ip6-chain
3328 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3329 * [0] [@2]: dpo-receive
3330 * ff02::1:ff00:0/104
3331 * unicast-ip6-chain
3332 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3333 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003334 * @cliexend
3335 * @endparblock
3336?*/
3337/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003338VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3339{
3340 .path = "set ip6 flow-hash",
3341 .short_help =
3342 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3343 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003344};
Billy McFall0683c9c2016-10-13 08:27:31 -04003345/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003346
3347static clib_error_t *
3348show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003349 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003350{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003351 ip6_main_t *im = &ip6_main;
3352 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003353 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003354
Ed Warnickecb9cada2015-12-08 15:45:58 -07003355 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003356 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003357 {
3358 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003359 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003360 }
3361 return 0;
3362}
3363
3364
3365
Billy McFall0683c9c2016-10-13 08:27:31 -04003366/*?
3367 * Display the set of protocols handled by the local IPv6 stack.
3368 *
3369 * @cliexpar
3370 * Example of how to display local protocol table:
3371 * @cliexstart{show ip6 local}
3372 * Protocols handled by ip6_local
3373 * 17
3374 * 43
3375 * 58
3376 * 115
3377 * @cliexend
3378?*/
3379/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003380VLIB_CLI_COMMAND (show_ip6_local, static) =
3381{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003382 .path = "show ip6 local",
3383 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003384 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003385};
Billy McFall0683c9c2016-10-13 08:27:31 -04003386/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003387
Dave Barachd7cb1b52016-12-09 09:52:16 -05003388int
3389vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3390 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003391{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003392 vnet_main_t *vnm = vnet_get_main ();
3393 vnet_interface_main_t *im = &vnm->interface_main;
3394 ip6_main_t *ipm = &ip6_main;
3395 ip_lookup_main_t *lm = &ipm->lookup_main;
3396 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003397 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003398
3399 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3400 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3401
3402 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3403 return VNET_API_ERROR_NO_SUCH_ENTRY;
3404
3405 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003406 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003407
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003408 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003409
3410 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003411 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003412 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003413 .fp_len = 128,
3414 .fp_proto = FIB_PROTOCOL_IP6,
3415 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003416 };
3417 u32 fib_index;
3418
Dave Barachd7cb1b52016-12-09 09:52:16 -05003419 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3420 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003421
3422
Dave Barachd7cb1b52016-12-09 09:52:16 -05003423 if (table_index != (u32) ~ 0)
3424 {
3425 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003426
Dave Barachd7cb1b52016-12-09 09:52:16 -05003427 dpo_set (&dpo,
3428 DPO_CLASSIFY,
3429 DPO_PROTO_IP6,
3430 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003431
Dave Barachd7cb1b52016-12-09 09:52:16 -05003432 fib_table_entry_special_dpo_add (fib_index,
3433 &pfx,
3434 FIB_SOURCE_CLASSIFY,
3435 FIB_ENTRY_FLAG_NONE, &dpo);
3436 dpo_reset (&dpo);
3437 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003438 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003439 {
3440 fib_table_entry_special_remove (fib_index,
3441 &pfx, FIB_SOURCE_CLASSIFY);
3442 }
3443 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003444
Ed Warnickecb9cada2015-12-08 15:45:58 -07003445 return 0;
3446}
3447
3448static clib_error_t *
3449set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003450 unformat_input_t * input,
3451 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003452{
3453 u32 table_index = ~0;
3454 int table_index_set = 0;
3455 u32 sw_if_index = ~0;
3456 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003457
Dave Barachd7cb1b52016-12-09 09:52:16 -05003458 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3459 {
3460 if (unformat (input, "table-index %d", &table_index))
3461 table_index_set = 1;
3462 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3463 vnet_get_main (), &sw_if_index))
3464 ;
3465 else
3466 break;
3467 }
Dave Barach75fc8542016-10-11 16:16:02 -04003468
Ed Warnickecb9cada2015-12-08 15:45:58 -07003469 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003470 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003471
Ed Warnickecb9cada2015-12-08 15:45:58 -07003472 if (sw_if_index == ~0)
3473 return clib_error_return (0, "interface / subif must be specified");
3474
3475 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3476
3477 switch (rv)
3478 {
3479 case 0:
3480 break;
3481
3482 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3483 return clib_error_return (0, "No such interface");
3484
3485 case VNET_API_ERROR_NO_SUCH_ENTRY:
3486 return clib_error_return (0, "No such classifier table");
3487 }
3488 return 0;
3489}
3490
Billy McFall0683c9c2016-10-13 08:27:31 -04003491/*?
3492 * Assign a classification table to an interface. The classification
3493 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3494 * commands. Once the table is create, use this command to filter packets
3495 * on an interface.
3496 *
3497 * @cliexpar
3498 * Example of how to assign a classification table to an interface:
3499 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3500?*/
3501/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003502VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3503{
3504 .path = "set ip6 classify",
3505 .short_help =
3506 "set ip6 classify intfc <interface> table-index <classify-idx>",
3507 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003508};
Billy McFall0683c9c2016-10-13 08:27:31 -04003509/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003510
3511static clib_error_t *
3512ip6_config (vlib_main_t * vm, unformat_input_t * input)
3513{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003514 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003515 uword heapsize = 0;
3516 u32 tmp;
3517 u32 nbuckets = 0;
3518
Dave Barachd7cb1b52016-12-09 09:52:16 -05003519 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3520 {
3521 if (unformat (input, "hash-buckets %d", &tmp))
3522 nbuckets = tmp;
3523 else if (unformat (input, "heap-size %dm", &tmp))
3524 heapsize = ((u64) tmp) << 20;
3525 else if (unformat (input, "heap-size %dM", &tmp))
3526 heapsize = ((u64) tmp) << 20;
3527 else if (unformat (input, "heap-size %dg", &tmp))
3528 heapsize = ((u64) tmp) << 30;
3529 else if (unformat (input, "heap-size %dG", &tmp))
3530 heapsize = ((u64) tmp) << 30;
3531 else
3532 return clib_error_return (0, "unknown input '%U'",
3533 format_unformat_error, input);
3534 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003535
3536 im->lookup_table_nbuckets = nbuckets;
3537 im->lookup_table_size = heapsize;
3538
3539 return 0;
3540}
3541
3542VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003543
3544/*
3545 * fd.io coding-style-patch-verification: ON
3546 *
3547 * Local Variables:
3548 * eval: (c-set-style "gnu")
3549 * End:
3550 */