blob: 4f9ad85432ff39d9d21fe44dc1d7b5417c2a13d4 [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 *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001001 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001002
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 *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001015 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016
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 *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001032 u32 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
rootc9d1c5b2017-08-15 12:58:31 -04001326always_inline u8
1327ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1328 u32 * udp_offset0)
1329{
1330 u32 proto0;
1331 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1332 if (proto0 != IP_PROTOCOL_UDP)
1333 {
1334 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1335 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1336 }
1337 return proto0;
1338}
1339
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001340/* *INDENT-OFF* */
1341VNET_FEATURE_ARC_INIT (ip6_local) =
1342{
1343 .arc_name = "ip6-local",
1344 .start_nodes = VNET_FEATURES ("ip6-local"),
1345};
1346/* *INDENT-ON* */
1347
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348static uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001349ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1350 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001352 ip6_main_t *im = &ip6_main;
1353 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001355 u32 *from, *to_next, n_left_from, n_left_to_next;
1356 vlib_node_runtime_t *error_node =
1357 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001358 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359
1360 from = vlib_frame_vector_args (frame);
1361 n_left_from = frame->n_vectors;
1362 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001363
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364 if (node->flags & VLIB_NODE_FLAG_TRACE)
1365 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1366
1367 while (n_left_from > 0)
1368 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001369 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001370
1371 while (n_left_from >= 4 && n_left_to_next >= 2)
1372 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001373 vlib_buffer_t *p0, *p1;
1374 ip6_header_t *ip0, *ip1;
1375 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 u32 pi0, ip_len0, udp_len0, flags0, next0;
1377 u32 pi1, ip_len1, udp_len1, flags1, next1;
1378 i32 len_diff0, len_diff1;
rootc9d1c5b2017-08-15 12:58:31 -04001379 u8 error0, type0, good_l4_csum0, is_tcp_udp0;
1380 u8 error1, type1, good_l4_csum1, is_tcp_udp1;
Shwethab78292e2016-09-13 11:51:00 +01001381 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001382
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383 pi0 = to_next[0] = from[0];
1384 pi1 = to_next[1] = from[1];
1385 from += 2;
1386 n_left_from -= 2;
1387 to_next += 2;
1388 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001389
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001390 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1391
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392 p0 = vlib_get_buffer (vm, pi0);
1393 p1 = vlib_get_buffer (vm, pi1);
1394
1395 ip0 = vlib_buffer_get_current (p0);
1396 ip1 = vlib_buffer_get_current (p1);
1397
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001398 if (head_of_feature_arc == 0)
1399 goto skip_checks;
1400
Damjan Marion072401e2017-07-13 18:53:27 +02001401 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1402 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001403
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1405 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1406
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 flags0 = p0->flags;
1408 flags1 = p1->flags;
1409
rootc9d1c5b2017-08-15 12:58:31 -04001410 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1411 is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
1412
1413 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1414 good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001415 len_diff0 = 0;
1416 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001417
rootc9d1c5b2017-08-15 12:58:31 -04001418 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001419 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001420 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001421 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001422 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001423 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001424 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001425 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1426 {
1427 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1428 udp_len0 = clib_net_to_host_u16 (udp0->length);
1429 len_diff0 = ip_len0 - udp_len0;
1430 }
Shwethab78292e2016-09-13 11:51:00 +01001431 }
rootc9d1c5b2017-08-15 12:58:31 -04001432 if (PREDICT_TRUE (is_tcp_udp1))
Shwethab78292e2016-09-13 11:51:00 +01001433 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001434 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001435 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001436 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001437 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001438 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001439 if (is_tcp_udp1 == IP_PROTOCOL_UDP)
1440 {
1441 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1442 udp_len1 = clib_net_to_host_u16 (udp1->length);
1443 len_diff1 = ip_len1 - udp_len1;
1444 }
Shwethab78292e2016-09-13 11:51:00 +01001445 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001446
rootc9d1c5b2017-08-15 12:58:31 -04001447 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1448 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1451 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1452
1453 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001454 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001455 && !(flags0 &
1456 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457 {
1458 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001459 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001460 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001461 }
1462 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001463 && !good_l4_csum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001464 && !(flags1 &
1465 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466 {
1467 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
rootc9d1c5b2017-08-15 12:58:31 -04001468 good_l4_csum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001469 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001470 }
1471
1472 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001473 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1474 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1475
Dave Barachd7cb1b52016-12-09 09:52:16 -05001476 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1477 IP6_ERROR_UDP_CHECKSUM);
1478 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1479 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001480 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1481 error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001482
1483 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001484 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001485 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1486 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001487 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301489 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001490 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001491 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001492 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1493 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001494 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301496 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001497 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001498 }
1499
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001500 skip_checks:
1501
1502 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1503 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1504
Dave Barachd7cb1b52016-12-09 09:52:16 -05001505 next0 =
1506 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1507 next1 =
1508 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001509
1510 p0->error = error_node->errors[error0];
1511 p1->error = error_node->errors[error1];
1512
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001513 if (head_of_feature_arc)
1514 {
1515 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1516 vnet_feature_arc_start (arc_index,
1517 vnet_buffer (p0)->sw_if_index
1518 [VLIB_RX], &next0, p0);
1519 if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1520 vnet_feature_arc_start (arc_index,
1521 vnet_buffer (p1)->sw_if_index
1522 [VLIB_RX], &next1, p1);
1523 }
1524
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1526 to_next, n_left_to_next,
1527 pi0, pi1, next0, next1);
1528 }
1529
1530 while (n_left_from > 0 && n_left_to_next > 0)
1531 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001532 vlib_buffer_t *p0;
1533 ip6_header_t *ip0;
1534 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001535 u32 pi0, ip_len0, udp_len0, flags0, next0;
1536 i32 len_diff0;
rootc9d1c5b2017-08-15 12:58:31 -04001537 u8 error0, type0, good_l4_csum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001538 u32 udp_offset0;
rootc9d1c5b2017-08-15 12:58:31 -04001539 u8 is_tcp_udp0;
Dave Barach75fc8542016-10-11 16:16:02 -04001540
Ed Warnickecb9cada2015-12-08 15:45:58 -07001541 pi0 = to_next[0] = from[0];
1542 from += 1;
1543 n_left_from -= 1;
1544 to_next += 1;
1545 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001546
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001547 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1548
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001550 ip0 = vlib_buffer_get_current (p0);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001551
1552 if (head_of_feature_arc == 0)
1553 goto skip_check;
1554
Damjan Marion072401e2017-07-13 18:53:27 +02001555 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001556
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001558 flags0 = p0->flags;
rootc9d1c5b2017-08-15 12:58:31 -04001559 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1560 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561
Shwethab78292e2016-09-13 11:51:00 +01001562 len_diff0 = 0;
rootc9d1c5b2017-08-15 12:58:31 -04001563 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001564 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001565 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
rootc9d1c5b2017-08-15 12:58:31 -04001566 /* Don't verify UDP checksum for packets with explicit zero
1567 * checksum. */
1568 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001569 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001570 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001571 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1572 {
1573 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1574 udp_len0 = clib_net_to_host_u16 (udp0->length);
1575 len_diff0 = ip_len0 - udp_len0;
1576 }
Shwethab78292e2016-09-13 11:51:00 +01001577 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578
rootc9d1c5b2017-08-15 12:58:31 -04001579 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001580 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1581
1582 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001583 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001584 && !(flags0 &
1585 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001586 {
1587 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001588 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001589 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001590 }
1591
1592 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001593 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1594
Dave Barachd7cb1b52016-12-09 09:52:16 -05001595 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1596 IP6_ERROR_UDP_CHECKSUM);
1597 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1598 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001599 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600
rootc9d1c5b2017-08-15 12:58:31 -04001601 /* If this is a neighbor solicitation (ICMP), skip src RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001602 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1603 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001604 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301606 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001607 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608 }
1609
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001610 skip_check:
1611
1612 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001613 next0 =
1614 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615 p0->error = error_node->errors[error0];
1616
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001617 if (head_of_feature_arc)
1618 {
1619 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1620 vnet_feature_arc_start (arc_index,
1621 vnet_buffer (p0)->sw_if_index
1622 [VLIB_RX], &next0, p0);
1623 }
1624
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1626 to_next, n_left_to_next,
1627 pi0, next0);
1628 }
Dave Barach75fc8542016-10-11 16:16:02 -04001629
Ed Warnickecb9cada2015-12-08 15:45:58 -07001630 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1631 }
1632
1633 return frame->n_vectors;
1634}
1635
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001636static uword
1637ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1638{
1639 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1640}
1641
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642/* *INDENT-OFF* */
1643VLIB_REGISTER_NODE (ip6_local_node, static) =
1644{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001645 .function = ip6_local,
1646 .name = "ip6-local",
1647 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001649 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001650 .next_nodes =
1651 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652 [IP_LOCAL_NEXT_DROP] = "error-drop",
1653 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1655 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1656 },
1657};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001658/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001661
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001662
1663static uword
1664ip6_local_end_of_arc (vlib_main_t * vm,
1665 vlib_node_runtime_t * node, vlib_frame_t * frame)
1666{
1667 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1668}
1669
1670/* *INDENT-OFF* */
1671VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
1672 .function = ip6_local_end_of_arc,
1673 .name = "ip6-local-end-of-arc",
1674 .vector_size = sizeof (u32),
1675
1676 .format_trace = format_ip6_forward_next_trace,
1677 .sibling_of = "ip6-local",
1678};
1679
1680VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
1681
1682VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1683 .arc_name = "ip6-local",
1684 .node_name = "ip6-local-end-of-arc",
1685 .runs_before = 0, /* not before any other features */
1686};
1687/* *INDENT-ON* */
1688
Dave Barachd7cb1b52016-12-09 09:52:16 -05001689void
1690ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001691{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001692 vlib_main_t *vm = vlib_get_main ();
1693 ip6_main_t *im = &ip6_main;
1694 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001695
1696 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001697 lm->local_next_by_ip_protocol[protocol] =
1698 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001699}
1700
Dave Barachd7cb1b52016-12-09 09:52:16 -05001701typedef enum
1702{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001703 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001704 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001705 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1706} ip6_discover_neighbor_next_t;
1707
Dave Barachd7cb1b52016-12-09 09:52:16 -05001708typedef enum
1709{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001710 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1711 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001712 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001713} ip6_discover_neighbor_error_t;
1714
1715static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001716ip6_discover_neighbor_inline (vlib_main_t * vm,
1717 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001718 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001719{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001720 vnet_main_t *vnm = vnet_get_main ();
1721 ip6_main_t *im = &ip6_main;
1722 ip_lookup_main_t *lm = &im->lookup_main;
1723 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001724 uword n_left_from, n_left_to_next_drop;
1725 static f64 time_last_seed_change = -1e100;
1726 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001727 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 f64 time_now;
1729 int bogus_length;
1730
1731 if (node->flags & VLIB_NODE_FLAG_TRACE)
1732 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1733
1734 time_now = vlib_time_now (vm);
1735 if (time_now - time_last_seed_change > 1e-3)
1736 {
1737 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001738 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1739 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001740 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1741 hash_seeds[i] = r[i];
1742
1743 /* Mark all hash keys as been not-seen before. */
1744 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1745 hash_bitmap[i] = 0;
1746
1747 time_last_seed_change = time_now;
1748 }
1749
1750 from = vlib_frame_vector_args (frame);
1751 n_left_from = frame->n_vectors;
1752
1753 while (n_left_from > 0)
1754 {
1755 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1756 to_next_drop, n_left_to_next_drop);
1757
1758 while (n_left_from > 0 && n_left_to_next_drop > 0)
1759 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 vlib_buffer_t *p0;
1761 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1763 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001764 ip_adjacency_t *adj0;
1765 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 u32 next0;
1767
1768 pi0 = from[0];
1769
1770 p0 = vlib_get_buffer (vm, pi0);
1771
1772 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1773
1774 ip0 = vlib_buffer_get_current (p0);
1775
Neale Ranns107e7d42017-04-11 09:55:19 -07001776 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001778 if (!is_glean)
1779 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001780 ip0->dst_address.as_u64[0] =
1781 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1782 ip0->dst_address.as_u64[1] =
1783 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001784 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001785
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 a0 = hash_seeds[0];
1787 b0 = hash_seeds[1];
1788 c0 = hash_seeds[2];
1789
1790 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1791 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1792
1793 a0 ^= sw_if_index0;
1794 b0 ^= ip0->dst_address.as_u32[0];
1795 c0 ^= ip0->dst_address.as_u32[1];
1796
1797 hash_v3_mix32 (a0, b0, c0);
1798
1799 b0 ^= ip0->dst_address.as_u32[2];
1800 c0 ^= ip0->dst_address.as_u32[3];
1801
1802 hash_v3_finalize32 (a0, b0, c0);
1803
1804 c0 &= BITS (hash_bitmap) - 1;
1805 c0 = c0 / BITS (uword);
1806 m0 = (uword) 1 << (c0 % BITS (uword));
1807
1808 bm0 = hash_bitmap[c0];
1809 drop0 = (bm0 & m0) != 0;
1810
1811 /* Mark it as seen. */
1812 hash_bitmap[c0] = bm0 | m0;
1813
1814 from += 1;
1815 n_left_from -= 1;
1816 to_next_drop[0] = pi0;
1817 to_next_drop += 1;
1818 n_left_to_next_drop -= 1;
1819
Dave Barachd7cb1b52016-12-09 09:52:16 -05001820 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001821
Dave Barachd7cb1b52016-12-09 09:52:16 -05001822 /* If the interface is link-down, drop the pkt */
1823 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1824 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001825
Dave Barach75fc8542016-10-11 16:16:02 -04001826 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1828 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829 if (drop0)
1830 continue;
1831
Neale Rannsb80c5362016-10-08 13:03:40 +01001832 /*
1833 * the adj has been updated to a rewrite but the node the DPO that got
1834 * us here hasn't - yet. no big deal. we'll drop while we wait.
1835 */
1836 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1837 continue;
1838
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839 {
1840 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841 icmp6_neighbor_solicitation_header_t *h0;
1842 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843
Dave Barach75fc8542016-10-11 16:16:02 -04001844 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001845 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846
Dave Barach75fc8542016-10-11 16:16:02 -04001847 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 * Build ethernet header.
1849 * Choose source address based on destination lookup
1850 * adjacency.
1851 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001852 if (ip6_src_address_for_packet (lm,
1853 sw_if_index0,
1854 &h0->ip.src_address))
1855 {
1856 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001857 p0->error =
1858 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1859 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001860 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001861 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001862
Dave Barach75fc8542016-10-11 16:16:02 -04001863 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001864 * Destination address is a solicited node multicast address.
1865 * We need to fill in
1866 * the low 24 bits with low 24 bits of target's address.
1867 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1869 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1870 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1871
1872 h0->neighbor.target_address = ip0->dst_address;
1873
Dave Barach75fc8542016-10-11 16:16:02 -04001874 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001875 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001876
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877 /* $$$$ appears we need this; why is the checksum non-zero? */
1878 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001879 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001880 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1881 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001884
1885 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1886 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001887 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001888 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001889
1890 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001891 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001892 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1893
John Lod1f5d042016-04-12 18:20:39 -04001894 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001895
1896 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1897 }
1898 }
1899
Dave Barach75fc8542016-10-11 16:16:02 -04001900 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001901 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902 }
1903
1904 return frame->n_vectors;
1905}
1906
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001907static uword
1908ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001909 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001910{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001911 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001912}
1913
1914static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001915ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001916{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001918}
1919
Dave Barachd7cb1b52016-12-09 09:52:16 -05001920static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001923 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1924 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001925};
1926
Dave Barachd7cb1b52016-12-09 09:52:16 -05001927/* *INDENT-OFF* */
1928VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1929{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930 .function = ip6_discover_neighbor,
1931 .name = "ip6-discover-neighbor",
1932 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001933 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001934 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1935 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001936 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001937 .next_nodes =
1938 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001939 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001940 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941 },
1942};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001943/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944
Dave Barachd7cb1b52016-12-09 09:52:16 -05001945/* *INDENT-OFF* */
1946VLIB_REGISTER_NODE (ip6_glean_node) =
1947{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001948 .function = ip6_glean,
1949 .name = "ip6-glean",
1950 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001951 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001952 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1953 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001954 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001955 .next_nodes =
1956 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001957 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1958 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1959 },
1960};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001961/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001962
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1965{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001966 vnet_main_t *vnm = vnet_get_main ();
1967 ip6_main_t *im = &ip6_main;
1968 icmp6_neighbor_solicitation_header_t *h;
1969 ip6_address_t *src;
1970 ip_interface_address_t *ia;
1971 ip_adjacency_t *adj;
1972 vnet_hw_interface_t *hi;
1973 vnet_sw_interface_t *si;
1974 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001975 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001976 u32 bi = 0;
1977 int bogus_length;
1978
1979 si = vnet_get_sw_interface (vnm, sw_if_index);
1980
1981 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1982 {
1983 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001984 format_ip6_address, dst,
1985 format_vnet_sw_if_index_name, vnm,
1986 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987 }
1988
Dave Barachd7cb1b52016-12-09 09:52:16 -05001989 src =
1990 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1991 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992 {
1993 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001994 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001995 (0, "no matching interface address for destination %U (interface %U)",
1996 format_ip6_address, dst,
1997 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998 }
1999
Dave Barachd7cb1b52016-12-09 09:52:16 -05002000 h =
2001 vlib_packet_template_get_packet (vm,
2002 &im->discover_neighbor_packet_template,
2003 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004
2005 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2006
2007 /* Destination address is a solicited node multicast address. We need to fill in
2008 the low 24 bits with low 24 bits of target's address. */
2009 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
2010 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
2011 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
2012
2013 h->ip.src_address = src[0];
2014 h->neighbor.target_address = dst[0];
2015
Pavel Kotucek57808982017-08-02 08:20:19 +02002016 if (PREDICT_FALSE (!hi->hw_address))
2017 {
2018 return clib_error_return (0, "%U: interface %U do not support ip probe",
2019 format_ip6_address, dst,
2020 format_vnet_sw_if_index_name, vnm,
2021 sw_if_index);
2022 }
2023
Dave Barachd7cb1b52016-12-09 09:52:16 -05002024 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
2025 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002026
Dave Barach75fc8542016-10-11 16:16:02 -04002027 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002029 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030
2031 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002032 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2033 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002034
2035 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07002036 ip46_address_t nh = {
2037 .ip6 = *dst,
2038 };
2039
2040 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
2041 VNET_LINK_IP6, &nh, sw_if_index);
2042 adj = adj_get (ai);
2043
Dave Barach59b25652017-09-10 15:04:27 -04002044 /* Peer has been previously resolved, retrieve glean adj instead */
2045 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2046 {
2047 adj_unlock (ai);
2048 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6, sw_if_index, &nh);
2049 adj = adj_get (ai);
2050 }
2051
Ed Warnickecb9cada2015-12-08 15:45:58 -07002052 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2053 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2054
2055 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002056 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2057 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002058 to_next[0] = bi;
2059 f->n_vectors = 1;
2060 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2061 }
2062
Neale Ranns7a272742017-05-30 02:08:14 -07002063 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002064 return /* no error */ 0;
2065}
2066
Dave Barachd7cb1b52016-12-09 09:52:16 -05002067typedef enum
2068{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002069 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002070 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002071} ip6_rewrite_next_t;
2072
2073always_inline uword
2074ip6_rewrite_inline (vlib_main_t * vm,
2075 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002076 vlib_frame_t * frame,
2077 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002078{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002079 ip_lookup_main_t *lm = &ip6_main.lookup_main;
2080 u32 *from = vlib_frame_vector_args (frame);
2081 u32 n_left_from, n_left_to_next, *to_next, next_index;
2082 vlib_node_runtime_t *error_node =
2083 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002084
2085 n_left_from = frame->n_vectors;
2086 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002087 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002088
Ed Warnickecb9cada2015-12-08 15:45:58 -07002089 while (n_left_from > 0)
2090 {
2091 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2092
2093 while (n_left_from >= 4 && n_left_to_next >= 2)
2094 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002095 ip_adjacency_t *adj0, *adj1;
2096 vlib_buffer_t *p0, *p1;
2097 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002098 u32 pi0, rw_len0, next0, error0, adj_index0;
2099 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002100 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04002101
Ed Warnickecb9cada2015-12-08 15:45:58 -07002102 /* Prefetch next iteration. */
2103 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002104 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002105
2106 p2 = vlib_get_buffer (vm, from[2]);
2107 p3 = vlib_get_buffer (vm, from[3]);
2108
2109 vlib_prefetch_buffer_header (p2, LOAD);
2110 vlib_prefetch_buffer_header (p3, LOAD);
2111
2112 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2113 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2114
2115 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2116 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2117 }
2118
2119 pi0 = to_next[0] = from[0];
2120 pi1 = to_next[1] = from[1];
2121
2122 from += 2;
2123 n_left_from -= 2;
2124 to_next += 2;
2125 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002126
Ed Warnickecb9cada2015-12-08 15:45:58 -07002127 p0 = vlib_get_buffer (vm, pi0);
2128 p1 = vlib_get_buffer (vm, pi1);
2129
Neale Rannsf06aea52016-11-29 06:51:37 -08002130 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2131 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002132
Ed Warnickecb9cada2015-12-08 15:45:58 -07002133 ip0 = vlib_buffer_get_current (p0);
2134 ip1 = vlib_buffer_get_current (p1);
2135
2136 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002137 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002138
Damjan Marion213b5aa2017-07-13 21:19:27 +02002139 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002140 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002141 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002142
2143 /* Input node should have reject packets with hop limit 0. */
2144 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002145
2146 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002147
2148 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150 /*
2151 * If the hop count drops below 1 when forwarding, generate
2152 * an ICMP response.
2153 */
2154 if (PREDICT_FALSE (hop_limit0 <= 0))
2155 {
2156 error0 = IP6_ERROR_TIME_EXPIRED;
2157 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2158 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2159 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2160 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2161 0);
2162 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002163 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164 else
2165 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002166 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002167 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002168 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002169 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002170 i32 hop_limit1 = ip1->hop_limit;
2171
2172 /* Input node should have reject packets with hop limit 0. */
2173 ASSERT (ip1->hop_limit > 0);
2174
2175 hop_limit1 -= 1;
2176
2177 ip1->hop_limit = hop_limit1;
2178
Dave Barachd7cb1b52016-12-09 09:52:16 -05002179 /*
2180 * If the hop count drops below 1 when forwarding, generate
2181 * an ICMP response.
2182 */
2183 if (PREDICT_FALSE (hop_limit1 <= 0))
2184 {
2185 error1 = IP6_ERROR_TIME_EXPIRED;
2186 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2187 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2188 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2189 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2190 0);
2191 }
2192 }
2193 else
2194 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002195 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002196 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002197 adj0 = adj_get (adj_index0);
2198 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002199
Ed Warnickecb9cada2015-12-08 15:45:58 -07002200 rw_len0 = adj0[0].rewrite_header.data_bytes;
2201 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002202 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2203 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002204
Neale Ranns9c6a6132017-02-21 05:33:14 -08002205 if (do_counters)
2206 {
2207 vlib_increment_combined_counter
2208 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002209 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002210 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2211 vlib_increment_combined_counter
2212 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002213 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002214 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2215 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002216
2217 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002218 error0 =
2219 (vlib_buffer_length_in_chain (vm, p0) >
2220 adj0[0].
2221 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2222 error0);
2223 error1 =
2224 (vlib_buffer_length_in_chain (vm, p1) >
2225 adj1[0].
2226 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2227 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228
Dave Barachd7cb1b52016-12-09 09:52:16 -05002229 /* Don't adjust the buffer for hop count issue; icmp-error node
2230 * wants to see the IP headerr */
2231 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2232 {
2233 p0->current_data -= rw_len0;
2234 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235
Dave Barachd7cb1b52016-12-09 09:52:16 -05002236 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2237 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2238 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002239
Neale Rannsb069a692017-03-15 12:34:25 -04002240 if (PREDICT_FALSE
2241 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2242 vnet_feature_arc_start (lm->output_feature_arc_index,
2243 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244 }
2245 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2246 {
2247 p1->current_data -= rw_len1;
2248 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249
Dave Barachd7cb1b52016-12-09 09:52:16 -05002250 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2251 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2252 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002253
Neale Rannsb069a692017-03-15 12:34:25 -04002254 if (PREDICT_FALSE
2255 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2256 vnet_feature_arc_start (lm->output_feature_arc_index,
2257 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002258 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002259
2260 /* Guess we are only writing on simple Ethernet header. */
2261 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002262 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002263
Neale Ranns5e575b12016-10-03 09:40:25 +01002264 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002265 {
2266 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2267 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2268 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002269 if (is_mcast)
2270 {
2271 /*
2272 * copy bytes from the IP address into the MAC rewrite
2273 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002274 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2275 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002276 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002277
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2279 to_next, n_left_to_next,
2280 pi0, pi1, next0, next1);
2281 }
2282
2283 while (n_left_from > 0 && n_left_to_next > 0)
2284 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002285 ip_adjacency_t *adj0;
2286 vlib_buffer_t *p0;
2287 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288 u32 pi0, rw_len0;
2289 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002290 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002291
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 pi0 = to_next[0] = from[0];
2293
2294 p0 = vlib_get_buffer (vm, pi0);
2295
Neale Rannsf06aea52016-11-29 06:51:37 -08002296 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297
Neale Ranns107e7d42017-04-11 09:55:19 -07002298 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002299
Ed Warnickecb9cada2015-12-08 15:45:58 -07002300 ip0 = vlib_buffer_get_current (p0);
2301
2302 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002303 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304
2305 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002306 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002307 {
2308 i32 hop_limit0 = ip0->hop_limit;
2309
2310 ASSERT (ip0->hop_limit > 0);
2311
2312 hop_limit0 -= 1;
2313
2314 ip0->hop_limit = hop_limit0;
2315
Dave Barachd7cb1b52016-12-09 09:52:16 -05002316 if (PREDICT_FALSE (hop_limit0 <= 0))
2317 {
2318 /*
2319 * If the hop count drops below 1 when forwarding, generate
2320 * an ICMP response.
2321 */
2322 error0 = IP6_ERROR_TIME_EXPIRED;
2323 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2324 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2325 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2326 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2327 0);
2328 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002329 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330 else
2331 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002332 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002333 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002334
Ed Warnickecb9cada2015-12-08 15:45:58 -07002335 /* Guess we are only writing on simple Ethernet header. */
2336 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002337
Ed Warnickecb9cada2015-12-08 15:45:58 -07002338 /* Update packet buffer attributes/set output interface. */
2339 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002340 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002341
Neale Ranns9c6a6132017-02-21 05:33:14 -08002342 if (do_counters)
2343 {
2344 vlib_increment_combined_counter
2345 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002346 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002347 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2348 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002349
2350 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002351 error0 =
2352 (vlib_buffer_length_in_chain (vm, p0) >
2353 adj0[0].
2354 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2355 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002356
Dave Barachd7cb1b52016-12-09 09:52:16 -05002357 /* Don't adjust the buffer for hop count issue; icmp-error node
2358 * wants to see the IP headerr */
2359 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2360 {
Chris Luke816f3e12016-06-14 16:24:47 -04002361 p0->current_data -= rw_len0;
2362 p0->current_length += rw_len0;
2363
Dave Barachd7cb1b52016-12-09 09:52:16 -05002364 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002365
Dave Barachd7cb1b52016-12-09 09:52:16 -05002366 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2367 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002368
Neale Rannsb069a692017-03-15 12:34:25 -04002369 if (PREDICT_FALSE
2370 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2371 vnet_feature_arc_start (lm->output_feature_arc_index,
2372 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002373 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002374
Neale Ranns5e575b12016-10-03 09:40:25 +01002375 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002376 {
2377 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2378 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002379 if (is_mcast)
2380 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002381 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002382 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002383
Ed Warnickecb9cada2015-12-08 15:45:58 -07002384 p0->error = error_node->errors[error0];
2385
2386 from += 1;
2387 n_left_from -= 1;
2388 to_next += 1;
2389 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002390
Ed Warnickecb9cada2015-12-08 15:45:58 -07002391 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2392 to_next, n_left_to_next,
2393 pi0, next0);
2394 }
2395
2396 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2397 }
2398
2399 /* Need to do trace after rewrites to pick up new packet data. */
2400 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002401 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402
2403 return frame->n_vectors;
2404}
2405
2406static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002407ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002408 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002410 if (adj_are_counters_enabled ())
2411 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2412 else
2413 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002414}
2415
2416static uword
2417ip6_rewrite_mcast (vlib_main_t * vm,
2418 vlib_node_runtime_t * node, vlib_frame_t * frame)
2419{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002420 if (adj_are_counters_enabled ())
2421 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2422 else
2423 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002424}
2425
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002426static uword
2427ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002429{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002430 if (adj_are_counters_enabled ())
2431 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2432 else
2433 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002434}
2435
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002436static uword
2437ip6_mcast_midchain (vlib_main_t * vm,
2438 vlib_node_runtime_t * node, vlib_frame_t * frame)
2439{
2440 if (adj_are_counters_enabled ())
2441 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2442 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002443 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002444}
2445
Dave Barachd7cb1b52016-12-09 09:52:16 -05002446/* *INDENT-OFF* */
2447VLIB_REGISTER_NODE (ip6_midchain_node) =
2448{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002449 .function = ip6_midchain,
2450 .name = "ip6-midchain",
2451 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002452 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002453 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002454 };
2455/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002456
Dave Barachd7cb1b52016-12-09 09:52:16 -05002457VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002458
Dave Barachd7cb1b52016-12-09 09:52:16 -05002459/* *INDENT-OFF* */
2460VLIB_REGISTER_NODE (ip6_rewrite_node) =
2461{
Neale Rannsf06aea52016-11-29 06:51:37 -08002462 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002463 .name = "ip6-rewrite",
2464 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002465 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002466 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002467 .next_nodes =
2468 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002469 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002470 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471 },
2472};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002474
Neale Rannsf06aea52016-11-29 06:51:37 -08002475VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002476
Neale Ranns32e1c012016-11-22 17:07:28 +00002477/* *INDENT-OFF* */
2478VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2479{
2480 .function = ip6_rewrite_mcast,
2481 .name = "ip6-rewrite-mcast",
2482 .vector_size = sizeof (u32),
2483 .format_trace = format_ip6_rewrite_trace,
2484 .sibling_of = "ip6-rewrite",
2485};
2486/* *INDENT-ON* */
2487
2488VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2489
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002490/* *INDENT-OFF* */
2491VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2492{
2493 .function = ip6_mcast_midchain,
2494 .name = "ip6-mcast-midchain",
2495 .vector_size = sizeof (u32),
2496 .format_trace = format_ip6_rewrite_trace,
2497 .sibling_of = "ip6-rewrite",
2498};
2499/* *INDENT-ON* */
2500
2501VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2502
Ole Troan944f5482016-05-24 11:56:58 +02002503/*
2504 * Hop-by-Hop handling
2505 */
Ole Troan944f5482016-05-24 11:56:58 +02002506ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2507
2508#define foreach_ip6_hop_by_hop_error \
2509_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2510_(FORMAT, "incorrectly formatted hop-by-hop options") \
2511_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2512
Neale Ranns32e1c012016-11-22 17:07:28 +00002513/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002514typedef enum
2515{
Ole Troan944f5482016-05-24 11:56:58 +02002516#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2517 foreach_ip6_hop_by_hop_error
2518#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002519 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002520} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002521/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002522
2523/*
2524 * Primary h-b-h handler trace support
2525 * We work pretty hard on the problem for obvious reasons
2526 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002527typedef struct
2528{
Ole Troan944f5482016-05-24 11:56:58 +02002529 u32 next_index;
2530 u32 trace_len;
2531 u8 option_data[256];
2532} ip6_hop_by_hop_trace_t;
2533
2534vlib_node_registration_t ip6_hop_by_hop_node;
2535
Dave Barachd7cb1b52016-12-09 09:52:16 -05002536static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002537#define _(sym,string) string,
2538 foreach_ip6_hop_by_hop_error
2539#undef _
2540};
2541
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302542u8 *
2543format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2544{
2545 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2546 int total_len = va_arg (*args, int);
2547 ip6_hop_by_hop_option_t *opt0, *limit0;
2548 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2549 u8 type0;
2550
2551 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2552 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2553
2554 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2555 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2556
2557 while (opt0 < limit0)
2558 {
2559 type0 = opt0->type;
2560 switch (type0)
2561 {
2562 case 0: /* Pad, just stop */
2563 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2564 break;
2565
2566 default:
2567 if (hm->trace[type0])
2568 {
2569 s = (*hm->trace[type0]) (s, opt0);
2570 }
2571 else
2572 {
2573 s =
2574 format (s, "\n unrecognized option %d length %d", type0,
2575 opt0->length);
2576 }
2577 opt0 =
2578 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2579 sizeof (ip6_hop_by_hop_option_t));
2580 break;
2581 }
2582 }
2583 return s;
2584}
2585
Ole Troan944f5482016-05-24 11:56:58 +02002586static u8 *
2587format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2588{
2589 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2590 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002591 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002592 ip6_hop_by_hop_header_t *hbh0;
2593 ip6_hop_by_hop_option_t *opt0, *limit0;
2594 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2595
2596 u8 type0;
2597
Dave Barachd7cb1b52016-12-09 09:52:16 -05002598 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002599
2600 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002601 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002602
Dave Barachd7cb1b52016-12-09 09:52:16 -05002603 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2604 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002605
Dave Barachd7cb1b52016-12-09 09:52:16 -05002606 while (opt0 < limit0)
2607 {
2608 type0 = opt0->type;
2609 switch (type0)
2610 {
2611 case 0: /* Pad, just stop */
2612 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2613 break;
Ole Troan944f5482016-05-24 11:56:58 +02002614
Dave Barachd7cb1b52016-12-09 09:52:16 -05002615 default:
2616 if (hm->trace[type0])
2617 {
2618 s = (*hm->trace[type0]) (s, opt0);
2619 }
2620 else
2621 {
2622 s =
2623 format (s, "\n unrecognized option %d length %d", type0,
2624 opt0->length);
2625 }
2626 opt0 =
2627 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2628 sizeof (ip6_hop_by_hop_option_t));
2629 break;
2630 }
Ole Troan944f5482016-05-24 11:56:58 +02002631 }
Ole Troan944f5482016-05-24 11:56:58 +02002632 return s;
2633}
2634
Dave Barachd7cb1b52016-12-09 09:52:16 -05002635always_inline u8
2636ip6_scan_hbh_options (vlib_buffer_t * b0,
2637 ip6_header_t * ip0,
2638 ip6_hop_by_hop_header_t * hbh0,
2639 ip6_hop_by_hop_option_t * opt0,
2640 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002641{
2642 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2643 u8 type0;
2644 u8 error0 = 0;
2645
2646 while (opt0 < limit0)
2647 {
2648 type0 = opt0->type;
2649 switch (type0)
2650 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002651 case 0: /* Pad1 */
2652 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002653 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002654 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002655 break;
2656 default:
2657 if (hm->options[type0])
2658 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002659 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2660 {
Shwethaa91cbe62016-08-08 15:51:04 +01002661 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002662 return (error0);
2663 }
Shwethaa91cbe62016-08-08 15:51:04 +01002664 }
2665 else
2666 {
2667 /* Unrecognized mandatory option, check the two high order bits */
2668 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2669 {
2670 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2671 break;
2672 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2673 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2674 *next0 = IP_LOOKUP_NEXT_DROP;
2675 break;
2676 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2677 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2678 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002679 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2680 ICMP6_parameter_problem_unrecognized_option,
2681 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002682 break;
2683 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2684 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002686 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002687 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2688 icmp6_error_set_vnet_buffer (b0,
2689 ICMP6_parameter_problem,
2690 ICMP6_parameter_problem_unrecognized_option,
2691 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002692 }
2693 else
2694 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002695 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002696 }
2697 break;
2698 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002699 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002700 }
2701 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002702 opt0 =
2703 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2704 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002705 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002706 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002707}
2708
Ole Troan944f5482016-05-24 11:56:58 +02002709/*
2710 * Process the Hop-by-Hop Options header
2711 */
2712static uword
2713ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002714 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002715{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002716 vlib_node_runtime_t *error_node =
2717 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002718 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2719 u32 n_left_from, *from, *to_next;
2720 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002721
2722 from = vlib_frame_vector_args (frame);
2723 n_left_from = frame->n_vectors;
2724 next_index = node->cached_next_index;
2725
Dave Barachd7cb1b52016-12-09 09:52:16 -05002726 while (n_left_from > 0)
2727 {
2728 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002729
Dave Barachd7cb1b52016-12-09 09:52:16 -05002730 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002731
Dave Barachd7cb1b52016-12-09 09:52:16 -05002732 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002733 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002734 u32 bi0, bi1;
2735 vlib_buffer_t *b0, *b1;
2736 u32 next0, next1;
2737 ip6_header_t *ip0, *ip1;
2738 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2739 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2740 u8 error0 = 0, error1 = 0;
2741
2742 /* Prefetch next iteration. */
2743 {
2744 vlib_buffer_t *p2, *p3;
2745
2746 p2 = vlib_get_buffer (vm, from[2]);
2747 p3 = vlib_get_buffer (vm, from[3]);
2748
2749 vlib_prefetch_buffer_header (p2, LOAD);
2750 vlib_prefetch_buffer_header (p3, LOAD);
2751
2752 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2753 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002754 }
2755
Dave Barachd7cb1b52016-12-09 09:52:16 -05002756 /* Speculatively enqueue b0, b1 to the current next frame */
2757 to_next[0] = bi0 = from[0];
2758 to_next[1] = bi1 = from[1];
2759 from += 2;
2760 to_next += 2;
2761 n_left_from -= 2;
2762 n_left_to_next -= 2;
2763
2764 b0 = vlib_get_buffer (vm, bi0);
2765 b1 = vlib_get_buffer (vm, bi1);
2766
2767 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2768 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002769 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002770 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002771 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002772
2773 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2774 next0 = adj0->lookup_next_index;
2775 next1 = adj1->lookup_next_index;
2776
2777 ip0 = vlib_buffer_get_current (b0);
2778 ip1 = vlib_buffer_get_current (b1);
2779 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2780 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2781 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2782 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2783 limit0 =
2784 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2785 ((hbh0->length + 1) << 3));
2786 limit1 =
2787 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2788 ((hbh1->length + 1) << 3));
2789
2790 /*
2791 * Basic validity checks
2792 */
2793 if ((hbh0->length + 1) << 3 >
2794 clib_net_to_host_u16 (ip0->payload_length))
2795 {
2796 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2797 next0 = IP_LOOKUP_NEXT_DROP;
2798 goto outdual;
2799 }
2800 /* Scan the set of h-b-h options, process ones that we understand */
2801 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2802
2803 if ((hbh1->length + 1) << 3 >
2804 clib_net_to_host_u16 (ip1->payload_length))
2805 {
2806 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2807 next1 = IP_LOOKUP_NEXT_DROP;
2808 goto outdual;
2809 }
2810 /* Scan the set of h-b-h options, process ones that we understand */
2811 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2812
2813 outdual:
2814 /* Has the classifier flagged this buffer for special treatment? */
2815 if (PREDICT_FALSE
2816 ((error0 == 0)
2817 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2818 next0 = hm->next_override;
2819
2820 /* Has the classifier flagged this buffer for special treatment? */
2821 if (PREDICT_FALSE
2822 ((error1 == 0)
2823 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2824 next1 = hm->next_override;
2825
2826 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2827 {
2828 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2829 {
2830 ip6_hop_by_hop_trace_t *t =
2831 vlib_add_trace (vm, node, b0, sizeof (*t));
2832 u32 trace_len = (hbh0->length + 1) << 3;
2833 t->next_index = next0;
2834 /* Capture the h-b-h option verbatim */
2835 trace_len =
2836 trace_len <
2837 ARRAY_LEN (t->option_data) ? trace_len :
2838 ARRAY_LEN (t->option_data);
2839 t->trace_len = trace_len;
2840 clib_memcpy (t->option_data, hbh0, trace_len);
2841 }
2842 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2843 {
2844 ip6_hop_by_hop_trace_t *t =
2845 vlib_add_trace (vm, node, b1, sizeof (*t));
2846 u32 trace_len = (hbh1->length + 1) << 3;
2847 t->next_index = next1;
2848 /* Capture the h-b-h option verbatim */
2849 trace_len =
2850 trace_len <
2851 ARRAY_LEN (t->option_data) ? trace_len :
2852 ARRAY_LEN (t->option_data);
2853 t->trace_len = trace_len;
2854 clib_memcpy (t->option_data, hbh1, trace_len);
2855 }
2856
2857 }
2858
2859 b0->error = error_node->errors[error0];
2860 b1->error = error_node->errors[error1];
2861
2862 /* verify speculative enqueue, maybe switch current next frame */
2863 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2864 n_left_to_next, bi0, bi1, next0,
2865 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002866 }
2867
Dave Barachd7cb1b52016-12-09 09:52:16 -05002868 while (n_left_from > 0 && n_left_to_next > 0)
2869 {
2870 u32 bi0;
2871 vlib_buffer_t *b0;
2872 u32 next0;
2873 ip6_header_t *ip0;
2874 ip6_hop_by_hop_header_t *hbh0;
2875 ip6_hop_by_hop_option_t *opt0, *limit0;
2876 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002877
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878 /* Speculatively enqueue b0 to the current next frame */
2879 bi0 = from[0];
2880 to_next[0] = bi0;
2881 from += 1;
2882 to_next += 1;
2883 n_left_from -= 1;
2884 n_left_to_next -= 1;
2885
2886 b0 = vlib_get_buffer (vm, bi0);
2887 /*
2888 * Default use the next_index from the adjacency.
2889 * A HBH option rarely redirects to a different node
2890 */
2891 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002892 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002893 next0 = adj0->lookup_next_index;
2894
2895 ip0 = vlib_buffer_get_current (b0);
2896 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2897 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2898 limit0 =
2899 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2900 ((hbh0->length + 1) << 3));
2901
2902 /*
2903 * Basic validity checks
2904 */
2905 if ((hbh0->length + 1) << 3 >
2906 clib_net_to_host_u16 (ip0->payload_length))
2907 {
2908 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2909 next0 = IP_LOOKUP_NEXT_DROP;
2910 goto out0;
2911 }
2912
2913 /* Scan the set of h-b-h options, process ones that we understand */
2914 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2915
2916 out0:
2917 /* Has the classifier flagged this buffer for special treatment? */
2918 if (PREDICT_FALSE
2919 ((error0 == 0)
2920 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2921 next0 = hm->next_override;
2922
2923 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2924 {
2925 ip6_hop_by_hop_trace_t *t =
2926 vlib_add_trace (vm, node, b0, sizeof (*t));
2927 u32 trace_len = (hbh0->length + 1) << 3;
2928 t->next_index = next0;
2929 /* Capture the h-b-h option verbatim */
2930 trace_len =
2931 trace_len <
2932 ARRAY_LEN (t->option_data) ? trace_len :
2933 ARRAY_LEN (t->option_data);
2934 t->trace_len = trace_len;
2935 clib_memcpy (t->option_data, hbh0, trace_len);
2936 }
2937
2938 b0->error = error_node->errors[error0];
2939
2940 /* verify speculative enqueue, maybe switch current next frame */
2941 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2942 n_left_to_next, bi0, next0);
2943 }
2944 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002945 }
Ole Troan944f5482016-05-24 11:56:58 +02002946 return frame->n_vectors;
2947}
2948
Dave Barachd7cb1b52016-12-09 09:52:16 -05002949/* *INDENT-OFF* */
2950VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2951{
Ole Troan944f5482016-05-24 11:56:58 +02002952 .function = ip6_hop_by_hop,
2953 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002954 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002955 .vector_size = sizeof (u32),
2956 .format_trace = format_ip6_hop_by_hop_trace,
2957 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002958 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002959 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002960 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002961};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002963
Dave Barach5331c722016-08-17 11:54:30 -04002964VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002965
2966static clib_error_t *
2967ip6_hop_by_hop_init (vlib_main_t * vm)
2968{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002969 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2970 memset (hm->options, 0, sizeof (hm->options));
2971 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002972 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002973 return (0);
2974}
2975
2976VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2977
Dave Barachd7cb1b52016-12-09 09:52:16 -05002978void
2979ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002980{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002981 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002982
2983 hm->next_override = next;
2984}
2985
Ole Troan944f5482016-05-24 11:56:58 +02002986int
2987ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002988 int options (vlib_buffer_t * b, ip6_header_t * ip,
2989 ip6_hop_by_hop_option_t * opt),
2990 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002991{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002992 ip6_main_t *im = &ip6_main;
2993 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002994
2995 ASSERT (option < ARRAY_LEN (hm->options));
2996
2997 /* Already registered */
2998 if (hm->options[option])
2999 return (-1);
3000
3001 hm->options[option] = options;
3002 hm->trace[option] = trace;
3003
3004 /* Set global variable */
3005 im->hbh_enabled = 1;
3006
3007 return (0);
3008}
3009
3010int
3011ip6_hbh_unregister_option (u8 option)
3012{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003013 ip6_main_t *im = &ip6_main;
3014 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02003015
3016 ASSERT (option < ARRAY_LEN (hm->options));
3017
3018 /* Not registered */
3019 if (!hm->options[option])
3020 return (-1);
3021
3022 hm->options[option] = NULL;
3023 hm->trace[option] = NULL;
3024
3025 /* Disable global knob if this was the last option configured */
3026 int i;
3027 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003028 for (i = 0; i < 256; i++)
3029 {
3030 if (hm->options[option])
3031 {
3032 found = true;
3033 break;
3034 }
Ole Troan944f5482016-05-24 11:56:58 +02003035 }
Ole Troan944f5482016-05-24 11:56:58 +02003036 if (!found)
3037 im->hbh_enabled = 0;
3038
3039 return (0);
3040}
3041
Ed Warnickecb9cada2015-12-08 15:45:58 -07003042/* Global IP6 main. */
3043ip6_main_t ip6_main;
3044
3045static clib_error_t *
3046ip6_lookup_init (vlib_main_t * vm)
3047{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003048 ip6_main_t *im = &ip6_main;
3049 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050 uword i;
3051
Damjan Marion8b3191e2016-11-09 19:54:20 +01003052 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
3053 return error;
3054
Ed Warnickecb9cada2015-12-08 15:45:58 -07003055 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
3056 {
3057 u32 j, i0, i1;
3058
3059 i0 = i / 32;
3060 i1 = i % 32;
3061
3062 for (j = 0; j < i0; j++)
3063 im->fib_masks[i].as_u32[j] = ~0;
3064
3065 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003066 im->fib_masks[i].as_u32[i0] =
3067 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068 }
3069
3070 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
3071
3072 if (im->lookup_table_nbuckets == 0)
3073 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
3074
Dave Barachd7cb1b52016-12-09 09:52:16 -05003075 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003076
3077 if (im->lookup_table_size == 0)
3078 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04003079
Dave Barachd7cb1b52016-12-09 09:52:16 -05003080 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
3081 "ip6 FIB fwding table",
3082 im->lookup_table_nbuckets, im->lookup_table_size);
3083 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
3084 "ip6 FIB non-fwding table",
3085 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003086
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07003088 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3089 FIB_SOURCE_DEFAULT_ROUTE);
3090 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3091 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092
3093 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003094 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095 pn = pg_get_node (ip6_lookup_node.index);
3096 pn->unformat_edit = unformat_pg_ip6_header;
3097 }
3098
Ole Troan944f5482016-05-24 11:56:58 +02003099 /* Unless explicitly configured, don't process HBH options */
3100 im->hbh_enabled = 0;
3101
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102 {
3103 icmp6_neighbor_solicitation_header_t p;
3104
3105 memset (&p, 0, sizeof (p));
3106
Dave Barachd7cb1b52016-12-09 09:52:16 -05003107 p.ip.ip_version_traffic_class_and_flow_label =
3108 clib_host_to_net_u32 (0x6 << 28);
3109 p.ip.payload_length =
3110 clib_host_to_net_u16 (sizeof (p) -
3111 STRUCT_OFFSET_OF
3112 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113 p.ip.protocol = IP_PROTOCOL_ICMP6;
3114 p.ip.hop_limit = 255;
3115 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3116
3117 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3118
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119 p.link_layer_option.header.type =
3120 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3121 p.link_layer_option.header.n_data_u64s =
3122 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123
3124 vlib_packet_template_init (vm,
3125 &im->discover_neighbor_packet_template,
3126 &p, sizeof (p),
3127 /* alloc chunk size */ 8,
3128 "ip6 neighbor discovery");
3129 }
3130
Dave Barach203c6322016-06-26 10:29:03 -04003131 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132}
3133
3134VLIB_INIT_FUNCTION (ip6_lookup_init);
3135
Dave Barach75fc8542016-10-11 16:16:02 -04003136void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003137ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3138 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139{
3140 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3141 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003142 ip->as_u8[8] = mac[0] ^ (1 << 1);
3143 ip->as_u8[9] = mac[1];
3144 ip->as_u8[10] = mac[2];
3145 ip->as_u8[11] = 0xFF;
3146 ip->as_u8[12] = 0xFE;
3147 ip->as_u8[13] = mac[3];
3148 ip->as_u8[14] = mac[4];
3149 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150}
3151
Dave Barach75fc8542016-10-11 16:16:02 -04003152void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003153ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3154 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155{
3156 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003157 mac[0] = ip->as_u8[8] ^ (1 << 1);
3158 mac[1] = ip->as_u8[9];
3159 mac[2] = ip->as_u8[10];
3160 mac[3] = ip->as_u8[13];
3161 mac[4] = ip->as_u8[14];
3162 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163}
3164
Dave Barach75fc8542016-10-11 16:16:02 -04003165static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003166test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003167 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003168{
3169 u8 mac[6];
3170 ip6_address_t _a, *a = &_a;
3171
3172 if (unformat (input, "%U", unformat_ethernet_address, mac))
3173 {
3174 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003175 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003176 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3177 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003178 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003179 }
Dave Barach75fc8542016-10-11 16:16:02 -04003180
Ed Warnickecb9cada2015-12-08 15:45:58 -07003181 return 0;
3182}
3183
Billy McFall0683c9c2016-10-13 08:27:31 -04003184/*?
3185 * This command converts the given MAC Address into an IPv6 link-local
3186 * address.
3187 *
3188 * @cliexpar
3189 * Example of how to create an IPv6 link-local address:
3190 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3191 * Link local address: fe80::14d9:e0ff:fe91:7986
3192 * Original MAC address: 16:d9:e0:91:79:86
3193 * @cliexend
3194?*/
3195/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003196VLIB_CLI_COMMAND (test_link_command, static) =
3197{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003198 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003199 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003200 .short_help = "test ip6 link <mac-address>",
3201};
Billy McFall0683c9c2016-10-13 08:27:31 -04003202/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203
Dave Barachd7cb1b52016-12-09 09:52:16 -05003204int
3205vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003206{
Neale Ranns107e7d42017-04-11 09:55:19 -07003207 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003208
Neale Ranns107e7d42017-04-11 09:55:19 -07003209 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003210
Neale Ranns107e7d42017-04-11 09:55:19 -07003211 if (~0 == fib_index)
3212 return VNET_API_ERROR_NO_SUCH_FIB;
3213
Neale Ranns227038a2017-04-21 01:07:59 -07003214 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3215 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003216
Neale Ranns227038a2017-04-21 01:07:59 -07003217 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003218}
3219
3220static clib_error_t *
3221set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003222 unformat_input_t * input,
3223 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003224{
3225 int matched = 0;
3226 u32 table_id = 0;
3227 u32 flow_hash_config = 0;
3228 int rv;
3229
Dave Barachd7cb1b52016-12-09 09:52:16 -05003230 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3231 {
3232 if (unformat (input, "table %d", &table_id))
3233 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003234#define _(a,v) \
3235 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003236 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003237#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003238 else
3239 break;
3240 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003241
3242 if (matched == 0)
3243 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003244 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003245
Ed Warnickecb9cada2015-12-08 15:45:58 -07003246 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3247 switch (rv)
3248 {
Neale Ranns227038a2017-04-21 01:07:59 -07003249 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003250 break;
3251
3252 case -1:
3253 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003254
Ed Warnickecb9cada2015-12-08 15:45:58 -07003255 default:
3256 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3257 break;
3258 }
Dave Barach75fc8542016-10-11 16:16:02 -04003259
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260 return 0;
3261}
3262
Billy McFall0683c9c2016-10-13 08:27:31 -04003263/*?
3264 * Configure the set of IPv6 fields used by the flow hash.
3265 *
3266 * @cliexpar
3267 * @parblock
3268 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003269 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3270 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003271 * Example of display the configured flow hash:
3272 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003273 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3274 * @::/0
3275 * unicast-ip6-chain
3276 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3277 * [0] [@0]: dpo-drop ip6
3278 * fe80::/10
3279 * unicast-ip6-chain
3280 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3281 * [0] [@2]: dpo-receive
3282 * ff02::1/128
3283 * unicast-ip6-chain
3284 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3285 * [0] [@2]: dpo-receive
3286 * ff02::2/128
3287 * unicast-ip6-chain
3288 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3289 * [0] [@2]: dpo-receive
3290 * ff02::16/128
3291 * unicast-ip6-chain
3292 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3293 * [0] [@2]: dpo-receive
3294 * ff02::1:ff00:0/104
3295 * unicast-ip6-chain
3296 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3297 * [0] [@2]: dpo-receive
3298 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3299 * @::/0
3300 * unicast-ip6-chain
3301 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3302 * [0] [@0]: dpo-drop ip6
3303 * @::a:1:1:0:4/126
3304 * unicast-ip6-chain
3305 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3306 * [0] [@4]: ipv6-glean: af_packet0
3307 * @::a:1:1:0:7/128
3308 * unicast-ip6-chain
3309 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3310 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3311 * fe80::/10
3312 * unicast-ip6-chain
3313 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3314 * [0] [@2]: dpo-receive
3315 * fe80::fe:3eff:fe3e:9222/128
3316 * unicast-ip6-chain
3317 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3318 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3319 * ff02::1/128
3320 * unicast-ip6-chain
3321 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3322 * [0] [@2]: dpo-receive
3323 * ff02::2/128
3324 * unicast-ip6-chain
3325 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3326 * [0] [@2]: dpo-receive
3327 * ff02::16/128
3328 * unicast-ip6-chain
3329 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3330 * [0] [@2]: dpo-receive
3331 * ff02::1:ff00:0/104
3332 * unicast-ip6-chain
3333 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3334 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003335 * @cliexend
3336 * @endparblock
3337?*/
3338/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003339VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3340{
3341 .path = "set ip6 flow-hash",
3342 .short_help =
3343 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3344 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003345};
Billy McFall0683c9c2016-10-13 08:27:31 -04003346/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003347
3348static clib_error_t *
3349show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003350 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003351{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003352 ip6_main_t *im = &ip6_main;
3353 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003354 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003355
Ed Warnickecb9cada2015-12-08 15:45:58 -07003356 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003357 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003358 {
3359 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02003360 {
3361
3362 u32 node_index = vlib_get_node (vm,
3363 ip6_local_node.index)->
3364 next_nodes[lm->local_next_by_ip_protocol[i]];
3365 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3366 node_index);
3367 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003368 }
3369 return 0;
3370}
3371
3372
3373
Billy McFall0683c9c2016-10-13 08:27:31 -04003374/*?
3375 * Display the set of protocols handled by the local IPv6 stack.
3376 *
3377 * @cliexpar
3378 * Example of how to display local protocol table:
3379 * @cliexstart{show ip6 local}
3380 * Protocols handled by ip6_local
3381 * 17
3382 * 43
3383 * 58
3384 * 115
3385 * @cliexend
3386?*/
3387/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003388VLIB_CLI_COMMAND (show_ip6_local, static) =
3389{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003390 .path = "show ip6 local",
3391 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003392 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003393};
Billy McFall0683c9c2016-10-13 08:27:31 -04003394/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003395
Dave Barachd7cb1b52016-12-09 09:52:16 -05003396int
3397vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3398 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003399{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003400 vnet_main_t *vnm = vnet_get_main ();
3401 vnet_interface_main_t *im = &vnm->interface_main;
3402 ip6_main_t *ipm = &ip6_main;
3403 ip_lookup_main_t *lm = &ipm->lookup_main;
3404 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003405 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003406
3407 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3408 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3409
3410 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3411 return VNET_API_ERROR_NO_SUCH_ENTRY;
3412
3413 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003414 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003415
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003416 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003417
3418 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003419 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003420 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003421 .fp_len = 128,
3422 .fp_proto = FIB_PROTOCOL_IP6,
3423 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003424 };
3425 u32 fib_index;
3426
Dave Barachd7cb1b52016-12-09 09:52:16 -05003427 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3428 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003429
3430
Dave Barachd7cb1b52016-12-09 09:52:16 -05003431 if (table_index != (u32) ~ 0)
3432 {
3433 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003434
Dave Barachd7cb1b52016-12-09 09:52:16 -05003435 dpo_set (&dpo,
3436 DPO_CLASSIFY,
3437 DPO_PROTO_IP6,
3438 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003439
Dave Barachd7cb1b52016-12-09 09:52:16 -05003440 fib_table_entry_special_dpo_add (fib_index,
3441 &pfx,
3442 FIB_SOURCE_CLASSIFY,
3443 FIB_ENTRY_FLAG_NONE, &dpo);
3444 dpo_reset (&dpo);
3445 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003446 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003447 {
3448 fib_table_entry_special_remove (fib_index,
3449 &pfx, FIB_SOURCE_CLASSIFY);
3450 }
3451 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003452
Ed Warnickecb9cada2015-12-08 15:45:58 -07003453 return 0;
3454}
3455
3456static clib_error_t *
3457set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003458 unformat_input_t * input,
3459 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003460{
3461 u32 table_index = ~0;
3462 int table_index_set = 0;
3463 u32 sw_if_index = ~0;
3464 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003465
Dave Barachd7cb1b52016-12-09 09:52:16 -05003466 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3467 {
3468 if (unformat (input, "table-index %d", &table_index))
3469 table_index_set = 1;
3470 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3471 vnet_get_main (), &sw_if_index))
3472 ;
3473 else
3474 break;
3475 }
Dave Barach75fc8542016-10-11 16:16:02 -04003476
Ed Warnickecb9cada2015-12-08 15:45:58 -07003477 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003478 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003479
Ed Warnickecb9cada2015-12-08 15:45:58 -07003480 if (sw_if_index == ~0)
3481 return clib_error_return (0, "interface / subif must be specified");
3482
3483 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3484
3485 switch (rv)
3486 {
3487 case 0:
3488 break;
3489
3490 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3491 return clib_error_return (0, "No such interface");
3492
3493 case VNET_API_ERROR_NO_SUCH_ENTRY:
3494 return clib_error_return (0, "No such classifier table");
3495 }
3496 return 0;
3497}
3498
Billy McFall0683c9c2016-10-13 08:27:31 -04003499/*?
3500 * Assign a classification table to an interface. The classification
3501 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3502 * commands. Once the table is create, use this command to filter packets
3503 * on an interface.
3504 *
3505 * @cliexpar
3506 * Example of how to assign a classification table to an interface:
3507 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3508?*/
3509/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003510VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3511{
3512 .path = "set ip6 classify",
3513 .short_help =
3514 "set ip6 classify intfc <interface> table-index <classify-idx>",
3515 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003516};
Billy McFall0683c9c2016-10-13 08:27:31 -04003517/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003518
3519static clib_error_t *
3520ip6_config (vlib_main_t * vm, unformat_input_t * input)
3521{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003522 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003523 uword heapsize = 0;
3524 u32 tmp;
3525 u32 nbuckets = 0;
3526
Dave Barachd7cb1b52016-12-09 09:52:16 -05003527 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3528 {
3529 if (unformat (input, "hash-buckets %d", &tmp))
3530 nbuckets = tmp;
3531 else if (unformat (input, "heap-size %dm", &tmp))
3532 heapsize = ((u64) tmp) << 20;
3533 else if (unformat (input, "heap-size %dM", &tmp))
3534 heapsize = ((u64) tmp) << 20;
3535 else if (unformat (input, "heap-size %dg", &tmp))
3536 heapsize = ((u64) tmp) << 30;
3537 else if (unformat (input, "heap-size %dG", &tmp))
3538 heapsize = ((u64) tmp) << 30;
3539 else
3540 return clib_error_return (0, "unknown input '%U'",
3541 format_unformat_error, input);
3542 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003543
3544 im->lookup_table_nbuckets = nbuckets;
3545 im->lookup_table_size = heapsize;
3546
3547 return 0;
3548}
3549
3550VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003551
3552/*
3553 * fd.io coding-style-patch-verification: ON
3554 *
3555 * Local Variables:
3556 * eval: (c-set-style "gnu")
3557 * End:
3558 */