blob: 5832bd0b5056180cb71a596ab5f9e298db3690cc [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
AkshayaNadahallied4a2fd2016-08-09 13:38:04 +05302 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip6_forward.c: IP v6 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +020042#include <vnet/ip/ip6_neighbor.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
45#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053046#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000048#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070049#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/bihash_template.c>
53
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053054/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
55#define OI_DECAP 0x80000000
56
Billy McFall0683c9c2016-10-13 08:27:31 -040057/**
58 * @file
59 * @brief IPv6 Forwarding.
60 *
61 * This file contains the source code for IPv6 forwarding.
62 */
63
Pierre Pfister0febaf12016-06-08 12:23:21 +010064void
65ip6_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050066 vlib_node_runtime_t * node,
67 vlib_frame_t * frame,
68 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010069
Damjan Marionaca64c92016-04-13 09:48:56 +020070always_inline uword
71ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050072 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070073{
Dave Barachd7cb1b52016-12-09 09:52:16 -050074 ip6_main_t *im = &ip6_main;
75 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
76 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020078 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 from = vlib_frame_vector_args (frame);
81 n_left_from = frame->n_vectors;
82 next = node->cached_next_index;
83
84 while (n_left_from > 0)
85 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050086 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
88 while (n_left_from >= 4 && n_left_to_next >= 2)
89 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050090 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010091 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050093 ip6_header_t *ip0, *ip1;
94 ip6_address_t *dst_addr0, *dst_addr1;
95 u32 fib_index0, fib_index1;
96 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010097 const dpo_id_t *dpo0, *dpo1;
98 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
100 /* Prefetch next iteration. */
101 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
104 p2 = vlib_get_buffer (vm, from[2]);
105 p3 = vlib_get_buffer (vm, from[3]);
106
107 vlib_prefetch_buffer_header (p2, LOAD);
108 vlib_prefetch_buffer_header (p3, LOAD);
109 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
110 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
111 }
112
113 pi0 = to_next[0] = from[0];
114 pi1 = to_next[1] = from[1];
115
116 p0 = vlib_get_buffer (vm, pi0);
117 p1 = vlib_get_buffer (vm, pi1);
118
119 ip0 = vlib_buffer_get_current (p0);
120 ip1 = vlib_buffer_get_current (p1);
121
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100122 dst_addr0 = &ip0->dst_address;
123 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200124
Dave Barachd7cb1b52016-12-09 09:52:16 -0500125 fib_index0 =
126 vec_elt (im->fib_index_by_sw_if_index,
127 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
128 fib_index1 =
129 vec_elt (im->fib_index_by_sw_if_index,
130 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Dave Barachd7cb1b52016-12-09 09:52:16 -0500132 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
133 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
134 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
135 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100137 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
138 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100140 lb0 = load_balance_get (lbi0);
141 lb1 = load_balance_get (lbi1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700142 ASSERT (lb0->lb_n_buckets > 0);
143 ASSERT (lb1->lb_n_buckets > 0);
144 ASSERT (is_pow2 (lb0->lb_n_buckets));
145 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Barachd7cb1b52016-12-09 09:52:16 -0500147 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148
Dave Barachd7cb1b52016-12-09 09:52:16 -0500149 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
150 {
151 flow_hash_config0 = lb0->lb_hash_config;
152 vnet_buffer (p0)->ip.flow_hash =
153 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700154 dpo0 =
155 load_balance_get_fwd_bucket (lb0,
156 (vnet_buffer (p0)->ip.flow_hash &
157 (lb0->lb_n_buckets_minus_1)));
158 }
159 else
160 {
161 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500162 }
163 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
164 {
165 flow_hash_config1 = lb1->lb_hash_config;
166 vnet_buffer (p1)->ip.flow_hash =
167 ip6_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700168 dpo1 =
169 load_balance_get_fwd_bucket (lb1,
170 (vnet_buffer (p1)->ip.flow_hash &
171 (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500172 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700173 else
174 {
175 dpo1 = load_balance_get_bucket_i (lb1, 0);
176 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100177 next0 = dpo0->dpoi_next_node;
178 next1 = dpo1->dpoi_next_node;
179
180 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 if (PREDICT_FALSE
182 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100183 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500184 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100185 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
186 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500187 if (PREDICT_FALSE
188 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100189 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100191 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
192 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100193 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
194 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach75fc8542016-10-11 16:16:02 -0400196 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200197 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400198 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200199 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
201 from += 2;
202 to_next += 2;
203 n_left_to_next -= 2;
204 n_left_from -= 2;
205
Dave Barachd7cb1b52016-12-09 09:52:16 -0500206 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500208 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 switch (wrong_next)
210 {
211 case 1:
212 /* A B A */
213 to_next[-2] = pi1;
214 to_next -= 1;
215 n_left_to_next += 1;
216 vlib_set_next_frame_buffer (vm, node, next0, pi0);
217 break;
218
219 case 2:
220 /* A A B */
221 to_next -= 1;
222 n_left_to_next += 1;
223 vlib_set_next_frame_buffer (vm, node, next1, pi1);
224 break;
225
226 case 3:
227 /* A B C */
228 to_next -= 2;
229 n_left_to_next += 2;
230 vlib_set_next_frame_buffer (vm, node, next0, pi0);
231 vlib_set_next_frame_buffer (vm, node, next1, pi1);
232 if (next0 == next1)
233 {
234 /* A B B */
235 vlib_put_next_frame (vm, node, next, n_left_to_next);
236 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 vlib_get_next_frame (vm, node, next, to_next,
238 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 }
240 }
241 }
242 }
Dave Barach75fc8542016-10-11 16:16:02 -0400243
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 while (n_left_from > 0 && n_left_to_next > 0)
245 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500246 vlib_buffer_t *p0;
247 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500250 load_balance_t *lb0;
251 ip6_address_t *dst_addr0;
252 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100253 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
255 pi0 = from[0];
256 to_next[0] = pi0;
257
258 p0 = vlib_get_buffer (vm, pi0);
259
260 ip0 = vlib_buffer_get_current (p0);
261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200263
Dave Barachd7cb1b52016-12-09 09:52:16 -0500264 fib_index0 =
265 vec_elt (im->fib_index_by_sw_if_index,
266 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
267 fib_index0 =
268 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
269 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100271 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100273 lb0 = load_balance_get (lbi0);
Neale Ranns227038a2017-04-21 01:07:59 -0700274 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
Dave Barachd7cb1b52016-12-09 09:52:16 -0500276 vnet_buffer (p0)->ip.flow_hash = 0;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700277 ASSERT (lb0->lb_n_buckets > 0);
278 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
Dave Barachd7cb1b52016-12-09 09:52:16 -0500280 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
281 {
282 flow_hash_config0 = lb0->lb_hash_config;
283 vnet_buffer (p0)->ip.flow_hash =
284 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700285 dpo0 =
286 load_balance_get_fwd_bucket (lb0,
287 (vnet_buffer (p0)->ip.flow_hash &
288 (lb0->lb_n_buckets_minus_1)));
289 }
290 else
291 {
292 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500293 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
Dave Barachd7cb1b52016-12-09 09:52:16 -0500295 dpo0 = load_balance_get_bucket_i (lb0,
296 (vnet_buffer (p0)->ip.flow_hash &
297 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299
Shwetha57fc8542016-09-27 08:04:05 +0100300 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500301 if (PREDICT_FALSE
302 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100303 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500304 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100305 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
306 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100307 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
Dave Barach75fc8542016-10-11 16:16:02 -0400309 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200310 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311
312 from += 1;
313 to_next += 1;
314 n_left_to_next -= 1;
315 n_left_from -= 1;
316
317 if (PREDICT_FALSE (next0 != next))
318 {
319 n_left_to_next += 1;
320 vlib_put_next_frame (vm, node, next, n_left_to_next);
321 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500322 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323 to_next[0] = pi0;
324 to_next += 1;
325 n_left_to_next -= 1;
326 }
327 }
328
329 vlib_put_next_frame (vm, node, next, n_left_to_next);
330 }
331
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100332 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100334
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 return frame->n_vectors;
336}
337
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338static void
339ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
340 ip6_main_t * im, u32 fib_index,
341 ip_interface_address_t * a)
342{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500343 ip_lookup_main_t *lm = &im->lookup_main;
344 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100345 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500346 .fp_len = a->address_length,
347 .fp_proto = FIB_PROTOCOL_IP6,
348 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100349 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500352 {
Neale Ranns7a272742017-05-30 02:08:14 -0700353 fib_table_entry_update_one_path (fib_index,
354 &pfx,
355 FIB_SOURCE_INTERFACE,
356 (FIB_ENTRY_FLAG_CONNECTED |
357 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700358 DPO_PROTO_IP6,
Neale Ranns7a272742017-05-30 02:08:14 -0700359 /* No next-hop address */
360 NULL, sw_if_index,
361 /* invalid FIB index */
362 ~0, 1,
363 /* no label stack */
364 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500365 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100367 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500369 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500371 lm->classify_table_index_by_sw_if_index[sw_if_index];
372 if (classify_table_index != (u32) ~ 0)
373 {
374 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 dpo_set (&dpo,
377 DPO_CLASSIFY,
378 DPO_PROTO_IP6,
379 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100380
Dave Barachd7cb1b52016-12-09 09:52:16 -0500381 fib_table_entry_special_dpo_add (fib_index,
382 &pfx,
383 FIB_SOURCE_CLASSIFY,
384 FIB_ENTRY_FLAG_NONE, &dpo);
385 dpo_reset (&dpo);
386 }
387 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100388
Neale Rannsf12a83f2017-04-18 09:09:40 -0700389 fib_table_entry_update_one_path (fib_index, &pfx,
390 FIB_SOURCE_INTERFACE,
391 (FIB_ENTRY_FLAG_CONNECTED |
392 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700393 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700394 &pfx.fp_addr,
395 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500396 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397}
398
399static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100400ip6_del_interface_routes (ip6_main_t * im,
401 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500402 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500404 fib_prefix_t pfx = {
405 .fp_len = address_length,
406 .fp_proto = FIB_PROTOCOL_IP6,
407 .fp_addr.ip6 = *address,
408 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
Dave Barachd7cb1b52016-12-09 09:52:16 -0500410 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500412 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100413
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 }
415
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416 pfx.fp_len = 128;
417 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418}
419
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100420void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500421ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500423 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100425 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100427 /*
428 * enable/disable only on the 1<->0 transition
429 */
430 if (is_enable)
431 {
432 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500433 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100434 }
435 else
436 {
Neale Ranns75152282017-01-09 01:00:45 -0800437 /* The ref count is 0 when an address is removed from an interface that has
438 * no address - this is not a ciritical error */
439 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
440 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500441 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100442 }
443
Neale Ranns630198f2017-05-22 09:20:20 -0400444 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
445 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446
Neale Ranns630198f2017-05-22 09:20:20 -0400447 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
448 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100449}
450
Neale Rannsdf089a82016-10-02 16:39:06 +0100451/* get first interface address */
452ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800453ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100454{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455 ip_lookup_main_t *lm = &im->lookup_main;
456 ip_interface_address_t *ia = 0;
457 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100458
Dave Barachd7cb1b52016-12-09 09:52:16 -0500459 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100460 foreach_ip_interface_address (lm, ia, sw_if_index,
461 1 /* honor unnumbered */,
462 ({
463 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
464 result = a;
465 break;
466 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100468 return result;
469}
470
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471clib_error_t *
472ip6_add_del_interface_address (vlib_main_t * vm,
473 u32 sw_if_index,
474 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500475 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 vnet_main_t *vnm = vnet_get_main ();
478 ip6_main_t *im = &ip6_main;
479 ip_lookup_main_t *lm = &im->lookup_main;
480 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483
Pavel Kotucek57808982017-08-02 08:20:19 +0200484 /* local0 interface doesn't support IP addressing */
485 if (sw_if_index == 0)
486 {
487 return
488 clib_error_create ("local0 interface doesn't support IP addressing");
489 }
490
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000492 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
493
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 ip6_addr_fib_init (&ip6_af, address,
495 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
496 vec_add1 (addr_fib, ip6_af);
497
498 {
499 uword elts_before = pool_elts (lm->if_address_pool);
500
501 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 if (error)
504 goto done;
505
506 /* Pool did not grow: add duplicate address. */
507 if (elts_before == pool_elts (lm->if_address_pool))
508 goto done;
509 }
510
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000512
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100513 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500514 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100515 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500516 ip6_add_interface_routes (vnm, sw_if_index,
517 im, ip6_af.fib_index,
518 pool_elt_at_index (lm->if_address_pool,
519 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520
521 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500522 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523 vec_foreach (cb, im->add_del_interface_address_callbacks)
524 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500525 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 }
527
Dave Barachd7cb1b52016-12-09 09:52:16 -0500528done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700529 vec_free (addr_fib);
530 return error;
531}
532
533clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 ip6_main_t *im = &ip6_main;
537 ip_interface_address_t *ia;
538 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539 u32 is_admin_up, fib_index;
540
541 /* Fill in lookup tables with default table (0). */
542 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
543
Dave Barachd7cb1b52016-12-09 09:52:16 -0500544 vec_validate_init_empty (im->
545 lookup_main.if_address_pool_index_by_sw_if_index,
546 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547
548 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
549
550 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
551
Dave Barachd7cb1b52016-12-09 09:52:16 -0500552 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400553 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 0 /* honor unnumbered */,
555 ({
556 a = ip_interface_address_get_address (&im->lookup_main, ia);
557 if (is_admin_up)
558 ip6_add_interface_routes (vnm, sw_if_index,
559 im, fib_index,
560 ia);
561 else
562 ip6_del_interface_routes (im, fib_index,
563 a, ia->address_length);
564 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500565 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566
567 return 0;
568}
569
570VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
571
Dave Barachd6534602016-06-14 18:38:02 -0400572/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500573/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100574VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
575{
576 .arc_name = "ip6-unicast",
577 .start_nodes = VNET_FEATURES ("ip6-input"),
578 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
579};
580
Dave Barachd7cb1b52016-12-09 09:52:16 -0500581VNET_FEATURE_INIT (ip6_flow_classify, static) =
582{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100583 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700584 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100585 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700586};
587
Dave Barachd7cb1b52016-12-09 09:52:16 -0500588VNET_FEATURE_INIT (ip6_inacl, static) =
589{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100590 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400591 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100592 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400593};
594
Dave Barachd7cb1b52016-12-09 09:52:16 -0500595VNET_FEATURE_INIT (ip6_policer_classify, static) =
596{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100597 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700598 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100599 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700600};
601
Dave Barachd7cb1b52016-12-09 09:52:16 -0500602VNET_FEATURE_INIT (ip6_ipsec, static) =
603{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100604 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400605 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100606 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400607};
608
Dave Barachd7cb1b52016-12-09 09:52:16 -0500609VNET_FEATURE_INIT (ip6_l2tp, static) =
610{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100611 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400612 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100613 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400614};
615
Dave Barachd7cb1b52016-12-09 09:52:16 -0500616VNET_FEATURE_INIT (ip6_vpath, static) =
617{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100618 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400619 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500620 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
621};
622
623VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
624{
625 .arc_name = "ip6-unicast",
626 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100627 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400628};
629
Dave Barachd7cb1b52016-12-09 09:52:16 -0500630VNET_FEATURE_INIT (ip6_drop, static) =
631{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100632 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100633 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400634 .runs_before = VNET_FEATURES ("ip6-lookup"),
635};
636
637VNET_FEATURE_INIT (ip6_lookup, static) =
638{
639 .arc_name = "ip6-unicast",
640 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642};
643
Dave Barachd6534602016-06-14 18:38:02 -0400644/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100645VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
646{
647 .arc_name = "ip6-multicast",
648 .start_nodes = VNET_FEATURES ("ip6-input"),
649 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
650};
651
652VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
653 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400654 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000655 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400656};
657
Damjan Marion8b3191e2016-11-09 19:54:20 +0100658VNET_FEATURE_INIT (ip6_drop_mc, static) = {
659 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100660 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400661 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
662};
663
664VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
665 .arc_name = "ip6-multicast",
666 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100667 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100668};
Dave Barach5331c722016-08-17 11:54:30 -0400669
670/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100671VNET_FEATURE_ARC_INIT (ip6_output, static) =
672{
673 .arc_name = "ip6-output",
674 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
675 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400676};
677
Matus Fabian08a6f012016-11-15 06:08:51 -0800678VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
679 .arc_name = "ip6-output",
680 .node_name = "ipsec-output-ip6",
681 .runs_before = VNET_FEATURES ("interface-output"),
682};
683
Damjan Marion8b3191e2016-11-09 19:54:20 +0100684VNET_FEATURE_INIT (ip6_interface_output, static) = {
685 .arc_name = "ip6-output",
686 .node_name = "interface-output",
687 .runs_before = 0, /* not before any other features */
688};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500689/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400690
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500692ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700694 ip6_main_t *im = &ip6_main;
695
696 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
697 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
698
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200699 if (!is_add)
700 {
701 /* Ensure that IPv6 is disabled */
702 ip6_main_t *im6 = &ip6_main;
703 ip_lookup_main_t *lm6 = &im6->lookup_main;
704 ip_interface_address_t *ia = 0;
705 ip6_address_t *address;
706 vlib_main_t *vm = vlib_get_main ();
707
708 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
709 /* *INDENT-OFF* */
710 foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* honor unnumbered */,
711 ({
712 address = ip_interface_address_get_address (lm6, ia);
713 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
714 }));
715 /* *INDENT-ON* */
716 ip6_mfib_interface_enable_disable (sw_if_index, 0);
717 }
718
Damjan Marion8b3191e2016-11-09 19:54:20 +0100719 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
720 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721
Damjan Marion8b3191e2016-11-09 19:54:20 +0100722 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
723 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725 return /* no error */ 0;
726}
727
728VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
729
Damjan Marionaca64c92016-04-13 09:48:56 +0200730static uword
731ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200733{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100734 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200735}
736
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100738
Dave Barachd7cb1b52016-12-09 09:52:16 -0500739/* *INDENT-OFF* */
740VLIB_REGISTER_NODE (ip6_lookup_node) =
741{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 .function = ip6_lookup,
743 .name = "ip6-lookup",
744 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100745 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200746 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200747 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500749/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750
Dave Barachd7cb1b52016-12-09 09:52:16 -0500751VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200752
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100753always_inline uword
754ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500755 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200756{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500757 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
758 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200760 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500761 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100762
763 from = vlib_frame_vector_args (frame);
764 n_left_from = frame->n_vectors;
765 next = node->cached_next_index;
766
767 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500768 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100769
770 while (n_left_from > 0)
771 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500772 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100773
Dave Barach75fc8542016-10-11 16:16:02 -0400774
Neale Ranns2be95c12016-11-19 13:50:04 +0000775 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500776 {
777 ip_lookup_next_t next0, next1;
778 const load_balance_t *lb0, *lb1;
779 vlib_buffer_t *p0, *p1;
780 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
781 const ip6_header_t *ip0, *ip1;
782 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000783
Dave Barachd7cb1b52016-12-09 09:52:16 -0500784 /* Prefetch next iteration. */
785 {
786 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000787
Dave Barachd7cb1b52016-12-09 09:52:16 -0500788 p2 = vlib_get_buffer (vm, from[2]);
789 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000790
Dave Barachd7cb1b52016-12-09 09:52:16 -0500791 vlib_prefetch_buffer_header (p2, STORE);
792 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000793
Dave Barachd7cb1b52016-12-09 09:52:16 -0500794 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
795 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
796 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000797
Dave Barachd7cb1b52016-12-09 09:52:16 -0500798 pi0 = to_next[0] = from[0];
799 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000800
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 from += 2;
802 n_left_from -= 2;
803 to_next += 2;
804 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000805
Dave Barachd7cb1b52016-12-09 09:52:16 -0500806 p0 = vlib_get_buffer (vm, pi0);
807 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000808
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 ip0 = vlib_buffer_get_current (p0);
810 ip1 = vlib_buffer_get_current (p1);
811 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
812 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000813
Dave Barachd7cb1b52016-12-09 09:52:16 -0500814 lb0 = load_balance_get (lbi0);
815 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000816
Dave Barachd7cb1b52016-12-09 09:52:16 -0500817 /*
818 * this node is for via FIBs we can re-use the hash value from the
819 * to node if present.
820 * We don't want to use the same hash value at each level in the recursion
821 * graph as that would lead to polarisation
822 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000823 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000824
Dave Barachd7cb1b52016-12-09 09:52:16 -0500825 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
826 {
827 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
828 {
829 hc0 = vnet_buffer (p0)->ip.flow_hash =
830 vnet_buffer (p0)->ip.flow_hash >> 1;
831 }
832 else
833 {
834 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000835 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500836 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700837 dpo0 =
838 load_balance_get_fwd_bucket (lb0,
839 (hc0 &
840 lb0->lb_n_buckets_minus_1));
841 }
842 else
843 {
844 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 }
846 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
847 {
848 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
849 {
850 hc1 = vnet_buffer (p1)->ip.flow_hash =
851 vnet_buffer (p1)->ip.flow_hash >> 1;
852 }
853 else
854 {
855 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000856 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700858 dpo1 =
859 load_balance_get_fwd_bucket (lb1,
860 (hc1 &
861 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700863 else
864 {
865 dpo1 = load_balance_get_bucket_i (lb1, 0);
866 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000867
Dave Barachd7cb1b52016-12-09 09:52:16 -0500868 next0 = dpo0->dpoi_next_node;
869 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000870
Dave Barachd7cb1b52016-12-09 09:52:16 -0500871 /* Only process the HBH Option Header if explicitly configured to do so */
872 if (PREDICT_FALSE
873 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
874 {
875 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
876 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
877 }
878 /* Only process the HBH Option Header if explicitly configured to do so */
879 if (PREDICT_FALSE
880 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
881 {
882 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
883 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
884 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000885
Dave Barachd7cb1b52016-12-09 09:52:16 -0500886 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
887 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000888
Dave Barachd7cb1b52016-12-09 09:52:16 -0500889 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200890 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500891 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200892 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000893
Dave Barachd7cb1b52016-12-09 09:52:16 -0500894 vlib_validate_buffer_enqueue_x2 (vm, node, next,
895 to_next, n_left_to_next,
896 pi0, pi1, next0, next1);
897 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000898
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100899 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500900 {
901 ip_lookup_next_t next0;
902 const load_balance_t *lb0;
903 vlib_buffer_t *p0;
904 u32 pi0, lbi0, hc0;
905 const ip6_header_t *ip0;
906 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100907
Dave Barachd7cb1b52016-12-09 09:52:16 -0500908 pi0 = from[0];
909 to_next[0] = pi0;
910 from += 1;
911 to_next += 1;
912 n_left_to_next -= 1;
913 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917 ip0 = vlib_buffer_get_current (p0);
918 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100919
Dave Barachd7cb1b52016-12-09 09:52:16 -0500920 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100921
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000922 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500923 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
924 {
925 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
926 {
927 hc0 = vnet_buffer (p0)->ip.flow_hash =
928 vnet_buffer (p0)->ip.flow_hash >> 1;
929 }
930 else
931 {
932 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000933 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700935 dpo0 =
936 load_balance_get_fwd_bucket (lb0,
937 (hc0 &
938 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700940 else
941 {
942 dpo0 = load_balance_get_bucket_i (lb0, 0);
943 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100944
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945 next0 = dpo0->dpoi_next_node;
946 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000947
Dave Barachd7cb1b52016-12-09 09:52:16 -0500948 /* Only process the HBH Option Header if explicitly configured to do so */
949 if (PREDICT_FALSE
950 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
951 {
952 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
953 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
954 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000955
Dave Barachd7cb1b52016-12-09 09:52:16 -0500956 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200957 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
Dave Barachd7cb1b52016-12-09 09:52:16 -0500959 vlib_validate_buffer_enqueue_x1 (vm, node, next,
960 to_next, n_left_to_next,
961 pi0, next0);
962 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100963
964 vlib_put_next_frame (vm, node, next, n_left_to_next);
965 }
966
967 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200968}
969
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970/* *INDENT-OFF* */
971VLIB_REGISTER_NODE (ip6_load_balance_node) =
972{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100973 .function = ip6_load_balance,
974 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200975 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200976 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100977 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200978};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500979/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200980
Dave Barachd7cb1b52016-12-09 09:52:16 -0500981VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200982
Dave Barachd7cb1b52016-12-09 09:52:16 -0500983typedef struct
984{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985 /* Adjacency taken. */
986 u32 adj_index;
987 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500988 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
990 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 u8 packet_data[128 - 1 * sizeof (u32)];
992}
993ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994
John Lo2b81eb82017-01-30 13:12:10 -0500995u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100998 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
999 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001000 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001001 uword indent = format_get_indent (s);
1002
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003 s = format (s, "%U%U",
1004 format_white_space, indent,
1005 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001006 return s;
1007}
1008
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009static u8 *
1010format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001011{
1012 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1013 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015 uword indent = format_get_indent (s);
1016
John Loac8146c2016-09-27 17:44:02 -04001017 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001018 t->fib_index, t->adj_index, t->flow_hash);
1019 s = format (s, "\n%U%U",
1020 format_white_space, indent,
1021 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001022 return s;
1023}
Pierre Pfister0febaf12016-06-08 12:23:21 +01001024
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026static u8 *
1027format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001028{
1029 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1030 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001032 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001034 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 t->fib_index, t->adj_index, format_ip_adjacency,
1036 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001037 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001038 format_white_space, indent,
1039 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001040 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041 return s;
1042}
1043
1044/* Common trace function for all ip6-forward next nodes. */
1045void
1046ip6_forward_next_trace (vlib_main_t * vm,
1047 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001048 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001050 u32 *from, n_left;
1051 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052
1053 n_left = frame->n_vectors;
1054 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001055
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056 while (n_left >= 4)
1057 {
1058 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001059 vlib_buffer_t *b0, *b1;
1060 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061
1062 /* Prefetch next iteration. */
1063 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1064 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1065
1066 bi0 = from[0];
1067 bi1 = from[1];
1068
1069 b0 = vlib_get_buffer (vm, bi0);
1070 b1 = vlib_get_buffer (vm, bi1);
1071
1072 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1073 {
1074 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1075 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001076 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1077 t0->fib_index =
1078 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1079 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1080 vec_elt (im->fib_index_by_sw_if_index,
1081 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001082
Damjan Marionf1213b82016-03-13 02:22:06 +01001083 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001084 vlib_buffer_get_current (b0),
1085 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086 }
1087 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1088 {
1089 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1090 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001091 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1092 t1->fib_index =
1093 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1094 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1095 vec_elt (im->fib_index_by_sw_if_index,
1096 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001097
Damjan Marionf1213b82016-03-13 02:22:06 +01001098 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001099 vlib_buffer_get_current (b1),
1100 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101 }
1102 from += 2;
1103 n_left -= 2;
1104 }
1105
1106 while (n_left >= 1)
1107 {
1108 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001109 vlib_buffer_t *b0;
1110 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111
1112 bi0 = from[0];
1113
1114 b0 = vlib_get_buffer (vm, bi0);
1115
1116 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1117 {
1118 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1119 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001120 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1121 t0->fib_index =
1122 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1123 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1124 vec_elt (im->fib_index_by_sw_if_index,
1125 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001126
Damjan Marionf1213b82016-03-13 02:22:06 +01001127 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128 vlib_buffer_get_current (b0),
1129 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001130 }
1131 from += 1;
1132 n_left -= 1;
1133 }
1134}
1135
1136static uword
1137ip6_drop_or_punt (vlib_main_t * vm,
1138 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 vlib_frame_t * frame, ip6_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001140{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001141 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 uword n_packets = frame->n_vectors;
1143
Dave Barachd7cb1b52016-12-09 09:52:16 -05001144 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 /* stride */ 1,
1146 n_packets,
1147 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 ip6_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149
1150 if (node->flags & VLIB_NODE_FLAG_TRACE)
1151 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1152
1153 return n_packets;
1154}
1155
1156static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001157ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1158{
1159 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1160}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161
1162static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1164{
1165 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1166}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167
Dave Barachd7cb1b52016-12-09 09:52:16 -05001168/* *INDENT-OFF* */
1169VLIB_REGISTER_NODE (ip6_drop_node, static) =
1170{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001171 .function = ip6_drop,
1172 .name = "ip6-drop",
1173 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001175 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176 .next_nodes =
1177 {
1178 [0] = "error-drop",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001183
Dave Barachd7cb1b52016-12-09 09:52:16 -05001184/* *INDENT-OFF* */
1185VLIB_REGISTER_NODE (ip6_punt_node, static) =
1186{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 .function = ip6_punt,
1188 .name = "ip6-punt",
1189 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001192 .next_nodes =
1193 {
1194 [0] = "error-punt",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001196/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001199
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001201u16
1202ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1203 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204{
1205 ip_csum_t sum0;
1206 u16 sum16, payload_length_host_byte_order;
1207 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001208 u32 headers_size = sizeof (ip0[0]);
1209 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001212 *bogus_lengthp = 0;
1213
1214 /* Initialize checksum with ip header. */
1215 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1216 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1217 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001218
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1220 {
1221 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 clib_mem_unaligned (&ip0->
1223 src_address.as_uword[i],
1224 uword));
1225 sum0 =
1226 ip_csum_with_carry (sum0,
1227 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1228 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229 }
1230
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301231 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1232 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001233 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001235 u32 skip_bytes;
1236 ip6_hop_by_hop_ext_t *ext_hdr =
1237 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001238
1239 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301240 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1241 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001242
Dave Barachd7cb1b52016-12-09 09:52:16 -05001243 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1244 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001245
Dave Barachd7cb1b52016-12-09 09:52:16 -05001246 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001248 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
1250 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001251 if (p0 && n_this_buffer + headers_size > p0->current_length)
1252 n_this_buffer =
1253 p0->current_length >
1254 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255 while (1)
1256 {
1257 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1258 n_bytes_left -= n_this_buffer;
1259 if (n_bytes_left == 0)
1260 break;
1261
1262 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001263 {
1264 *bogus_lengthp = 1;
1265 return 0xfefe;
1266 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267 p0 = vlib_get_buffer (vm, p0->next_buffer);
1268 data_this_buffer = vlib_buffer_get_current (p0);
1269 n_this_buffer = p0->current_length;
1270 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001273
1274 return sum16;
1275}
1276
Dave Barachd7cb1b52016-12-09 09:52:16 -05001277u32
1278ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001280 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1281 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282 u16 sum16;
1283 int bogus_length;
1284
1285 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1286 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1287 || ip0->protocol == IP_PROTOCOL_ICMP6
1288 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001289 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 udp0 = (void *) (ip0 + 1);
1292 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1293 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001294 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1295 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296 return p0->flags;
1297 }
1298
1299 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1300
Damjan Marion213b5aa2017-07-13 21:19:27 +02001301 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1302 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303
1304 return p0->flags;
1305}
1306
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301307/**
1308 * @brief returns number of links on which src is reachable.
1309 */
1310always_inline int
1311ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1312{
1313 const load_balance_t *lb0;
1314 index_t lbi;
1315
1316 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1317 vnet_buffer
1318 (b)->sw_if_index[VLIB_RX],
1319 &i->src_address);
1320
1321 lb0 = load_balance_get (lbi);
1322
1323 return (fib_urpf_check_size (lb0->lb_urpf));
1324}
1325
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
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001341ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001343 ip6_main_t *im = &ip6_main;
1344 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001345 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001346 u32 *from, *to_next, n_left_from, n_left_to_next;
1347 vlib_node_runtime_t *error_node =
1348 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349
1350 from = vlib_frame_vector_args (frame);
1351 n_left_from = frame->n_vectors;
1352 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001353
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354 if (node->flags & VLIB_NODE_FLAG_TRACE)
1355 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1356
1357 while (n_left_from > 0)
1358 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001359 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360
1361 while (n_left_from >= 4 && n_left_to_next >= 2)
1362 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001363 vlib_buffer_t *p0, *p1;
1364 ip6_header_t *ip0, *ip1;
1365 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001366 u32 pi0, ip_len0, udp_len0, flags0, next0;
1367 u32 pi1, ip_len1, udp_len1, flags1, next1;
1368 i32 len_diff0, len_diff1;
rootc9d1c5b2017-08-15 12:58:31 -04001369 u8 error0, type0, good_l4_csum0, is_tcp_udp0;
1370 u8 error1, type1, good_l4_csum1, is_tcp_udp1;
Shwethab78292e2016-09-13 11:51:00 +01001371 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001372
Ed Warnickecb9cada2015-12-08 15:45:58 -07001373 pi0 = to_next[0] = from[0];
1374 pi1 = to_next[1] = from[1];
1375 from += 2;
1376 n_left_from -= 2;
1377 to_next += 2;
1378 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001379
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380 p0 = vlib_get_buffer (vm, pi0);
1381 p1 = vlib_get_buffer (vm, pi1);
1382
1383 ip0 = vlib_buffer_get_current (p0);
1384 ip1 = vlib_buffer_get_current (p1);
1385
Damjan Marion072401e2017-07-13 18:53:27 +02001386 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1387 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001388
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1390 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1391
1392 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1393 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1394
1395 flags0 = p0->flags;
1396 flags1 = p1->flags;
1397
rootc9d1c5b2017-08-15 12:58:31 -04001398 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1399 is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
1400
1401 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1402 good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001403 len_diff0 = 0;
1404 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405
rootc9d1c5b2017-08-15 12:58:31 -04001406 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001407 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001408 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001409 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001410 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001411 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001412 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001413 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1414 {
1415 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1416 udp_len0 = clib_net_to_host_u16 (udp0->length);
1417 len_diff0 = ip_len0 - udp_len0;
1418 }
Shwethab78292e2016-09-13 11:51:00 +01001419 }
rootc9d1c5b2017-08-15 12:58:31 -04001420 if (PREDICT_TRUE (is_tcp_udp1))
Shwethab78292e2016-09-13 11:51:00 +01001421 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001422 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001423 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001424 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001425 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001426 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001427 if (is_tcp_udp1 == IP_PROTOCOL_UDP)
1428 {
1429 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1430 udp_len1 = clib_net_to_host_u16 (udp1->length);
1431 len_diff1 = ip_len1 - udp_len1;
1432 }
Shwethab78292e2016-09-13 11:51:00 +01001433 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434
rootc9d1c5b2017-08-15 12:58:31 -04001435 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1436 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437
Ed Warnickecb9cada2015-12-08 15:45:58 -07001438 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1439 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1440
1441 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001442 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001443 && !(flags0 &
1444 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001445 {
1446 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001447 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001448 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449 }
1450 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001451 && !good_l4_csum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001452 && !(flags1 &
1453 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001454 {
1455 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
rootc9d1c5b2017-08-15 12:58:31 -04001456 good_l4_csum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001457 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458 }
1459
1460 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001461 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1462 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1463
Dave Barachd7cb1b52016-12-09 09:52:16 -05001464 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1465 IP6_ERROR_UDP_CHECKSUM);
1466 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1467 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001468 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1469 error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001470
1471 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001472 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001473 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1474 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001475 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001476 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301477 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001478 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001479 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001480 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1481 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001482 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001483 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301484 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001485 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001486 }
1487
Dave Barachd7cb1b52016-12-09 09:52:16 -05001488 next0 =
1489 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1490 next1 =
1491 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001492
1493 p0->error = error_node->errors[error0];
1494 p1->error = error_node->errors[error1];
1495
1496 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1497 to_next, n_left_to_next,
1498 pi0, pi1, next0, next1);
1499 }
1500
1501 while (n_left_from > 0 && n_left_to_next > 0)
1502 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001503 vlib_buffer_t *p0;
1504 ip6_header_t *ip0;
1505 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506 u32 pi0, ip_len0, udp_len0, flags0, next0;
1507 i32 len_diff0;
rootc9d1c5b2017-08-15 12:58:31 -04001508 u8 error0, type0, good_l4_csum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001509 u32 udp_offset0;
rootc9d1c5b2017-08-15 12:58:31 -04001510 u8 is_tcp_udp0;
Dave Barach75fc8542016-10-11 16:16:02 -04001511
Ed Warnickecb9cada2015-12-08 15:45:58 -07001512 pi0 = to_next[0] = from[0];
1513 from += 1;
1514 n_left_from -= 1;
1515 to_next += 1;
1516 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001517
Ed Warnickecb9cada2015-12-08 15:45:58 -07001518 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001519 ip0 = vlib_buffer_get_current (p0);
Damjan Marion072401e2017-07-13 18:53:27 +02001520 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001521
Ed Warnickecb9cada2015-12-08 15:45:58 -07001522 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1523 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001524 flags0 = p0->flags;
rootc9d1c5b2017-08-15 12:58:31 -04001525 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1526 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527
Shwethab78292e2016-09-13 11:51:00 +01001528 len_diff0 = 0;
rootc9d1c5b2017-08-15 12:58:31 -04001529 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001530 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001531 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
rootc9d1c5b2017-08-15 12:58:31 -04001532 /* Don't verify UDP checksum for packets with explicit zero
1533 * checksum. */
1534 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001535 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001536 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001537 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1538 {
1539 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1540 udp_len0 = clib_net_to_host_u16 (udp0->length);
1541 len_diff0 = ip_len0 - udp_len0;
1542 }
Shwethab78292e2016-09-13 11:51:00 +01001543 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544
rootc9d1c5b2017-08-15 12:58:31 -04001545 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001546 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1547
1548 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001549 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001550 && !(flags0 &
1551 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001552 {
1553 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001554 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001555 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001556 }
1557
1558 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001559 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1560
Dave Barachd7cb1b52016-12-09 09:52:16 -05001561 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1562 IP6_ERROR_UDP_CHECKSUM);
1563 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1564 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001565 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001566
rootc9d1c5b2017-08-15 12:58:31 -04001567 /* If this is a neighbor solicitation (ICMP), skip src RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001568 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1569 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001570 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001571 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301572 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001573 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001574 }
1575
Dave Barachd7cb1b52016-12-09 09:52:16 -05001576 next0 =
1577 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578 p0->error = error_node->errors[error0];
1579
1580 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1581 to_next, n_left_to_next,
1582 pi0, next0);
1583 }
Dave Barach75fc8542016-10-11 16:16:02 -04001584
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1586 }
1587
1588 return frame->n_vectors;
1589}
1590
Dave Barachd7cb1b52016-12-09 09:52:16 -05001591/* *INDENT-OFF* */
1592VLIB_REGISTER_NODE (ip6_local_node, static) =
1593{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594 .function = ip6_local,
1595 .name = "ip6-local",
1596 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001599 .next_nodes =
1600 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601 [IP_LOCAL_NEXT_DROP] = "error-drop",
1602 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1604 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1605 },
1606};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001607/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608
Dave Barachd7cb1b52016-12-09 09:52:16 -05001609VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001610
Dave Barachd7cb1b52016-12-09 09:52:16 -05001611void
1612ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001614 vlib_main_t *vm = vlib_get_main ();
1615 ip6_main_t *im = &ip6_main;
1616 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617
1618 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001619 lm->local_next_by_ip_protocol[protocol] =
1620 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621}
1622
Dave Barachd7cb1b52016-12-09 09:52:16 -05001623typedef enum
1624{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001626 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001627 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1628} ip6_discover_neighbor_next_t;
1629
Dave Barachd7cb1b52016-12-09 09:52:16 -05001630typedef enum
1631{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1633 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001634 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635} ip6_discover_neighbor_error_t;
1636
1637static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001638ip6_discover_neighbor_inline (vlib_main_t * vm,
1639 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001640 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 vnet_main_t *vnm = vnet_get_main ();
1643 ip6_main_t *im = &ip6_main;
1644 ip_lookup_main_t *lm = &im->lookup_main;
1645 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 uword n_left_from, n_left_to_next_drop;
1647 static f64 time_last_seed_change = -1e100;
1648 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001649 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001650 f64 time_now;
1651 int bogus_length;
1652
1653 if (node->flags & VLIB_NODE_FLAG_TRACE)
1654 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1655
1656 time_now = vlib_time_now (vm);
1657 if (time_now - time_last_seed_change > 1e-3)
1658 {
1659 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1661 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001662 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1663 hash_seeds[i] = r[i];
1664
1665 /* Mark all hash keys as been not-seen before. */
1666 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1667 hash_bitmap[i] = 0;
1668
1669 time_last_seed_change = time_now;
1670 }
1671
1672 from = vlib_frame_vector_args (frame);
1673 n_left_from = frame->n_vectors;
1674
1675 while (n_left_from > 0)
1676 {
1677 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1678 to_next_drop, n_left_to_next_drop);
1679
1680 while (n_left_from > 0 && n_left_to_next_drop > 0)
1681 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001682 vlib_buffer_t *p0;
1683 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001684 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1685 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001686 ip_adjacency_t *adj0;
1687 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001688 u32 next0;
1689
1690 pi0 = from[0];
1691
1692 p0 = vlib_get_buffer (vm, pi0);
1693
1694 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1695
1696 ip0 = vlib_buffer_get_current (p0);
1697
Neale Ranns107e7d42017-04-11 09:55:19 -07001698 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001699
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001700 if (!is_glean)
1701 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 ip0->dst_address.as_u64[0] =
1703 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1704 ip0->dst_address.as_u64[1] =
1705 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001706 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001707
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708 a0 = hash_seeds[0];
1709 b0 = hash_seeds[1];
1710 c0 = hash_seeds[2];
1711
1712 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1713 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1714
1715 a0 ^= sw_if_index0;
1716 b0 ^= ip0->dst_address.as_u32[0];
1717 c0 ^= ip0->dst_address.as_u32[1];
1718
1719 hash_v3_mix32 (a0, b0, c0);
1720
1721 b0 ^= ip0->dst_address.as_u32[2];
1722 c0 ^= ip0->dst_address.as_u32[3];
1723
1724 hash_v3_finalize32 (a0, b0, c0);
1725
1726 c0 &= BITS (hash_bitmap) - 1;
1727 c0 = c0 / BITS (uword);
1728 m0 = (uword) 1 << (c0 % BITS (uword));
1729
1730 bm0 = hash_bitmap[c0];
1731 drop0 = (bm0 & m0) != 0;
1732
1733 /* Mark it as seen. */
1734 hash_bitmap[c0] = bm0 | m0;
1735
1736 from += 1;
1737 n_left_from -= 1;
1738 to_next_drop[0] = pi0;
1739 to_next_drop += 1;
1740 n_left_to_next_drop -= 1;
1741
Dave Barachd7cb1b52016-12-09 09:52:16 -05001742 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743
Dave Barachd7cb1b52016-12-09 09:52:16 -05001744 /* If the interface is link-down, drop the pkt */
1745 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1746 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747
Dave Barach75fc8542016-10-11 16:16:02 -04001748 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1750 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 if (drop0)
1752 continue;
1753
Neale Rannsb80c5362016-10-08 13:03:40 +01001754 /*
1755 * the adj has been updated to a rewrite but the node the DPO that got
1756 * us here hasn't - yet. no big deal. we'll drop while we wait.
1757 */
1758 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1759 continue;
1760
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 {
1762 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 icmp6_neighbor_solicitation_header_t *h0;
1764 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765
Dave Barach75fc8542016-10-11 16:16:02 -04001766 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001767 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768
Dave Barach75fc8542016-10-11 16:16:02 -04001769 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 * Build ethernet header.
1771 * Choose source address based on destination lookup
1772 * adjacency.
1773 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001774 if (ip6_src_address_for_packet (lm,
1775 sw_if_index0,
1776 &h0->ip.src_address))
1777 {
1778 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 p0->error =
1780 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1781 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001782 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001783 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001784
Dave Barach75fc8542016-10-11 16:16:02 -04001785 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001786 * Destination address is a solicited node multicast address.
1787 * We need to fill in
1788 * the low 24 bits with low 24 bits of target's address.
1789 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001790 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1791 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1792 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1793
1794 h0->neighbor.target_address = ip0->dst_address;
1795
Dave Barach75fc8542016-10-11 16:16:02 -04001796 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001797 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 /* $$$$ appears we need this; why is the checksum non-zero? */
1800 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001801 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001802 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1803 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804
Dave Barachd7cb1b52016-12-09 09:52:16 -05001805 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806
1807 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1808 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001809 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001810 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811
1812 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001813 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1815
John Lod1f5d042016-04-12 18:20:39 -04001816 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817
1818 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1819 }
1820 }
1821
Dave Barach75fc8542016-10-11 16:16:02 -04001822 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 }
1825
1826 return frame->n_vectors;
1827}
1828
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001829static uword
1830ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001831 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001832{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001833 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001834}
1835
1836static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001838{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001840}
1841
Dave Barachd7cb1b52016-12-09 09:52:16 -05001842static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001844 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001845 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1846 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847};
1848
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849/* *INDENT-OFF* */
1850VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1851{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852 .function = ip6_discover_neighbor,
1853 .name = "ip6-discover-neighbor",
1854 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1857 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001859 .next_nodes =
1860 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001862 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863 },
1864};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001865/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867/* *INDENT-OFF* */
1868VLIB_REGISTER_NODE (ip6_glean_node) =
1869{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001870 .function = ip6_glean,
1871 .name = "ip6-glean",
1872 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001873 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001874 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1875 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001876 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877 .next_nodes =
1878 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001879 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1880 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1881 },
1882};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001884
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1887{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001888 vnet_main_t *vnm = vnet_get_main ();
1889 ip6_main_t *im = &ip6_main;
1890 icmp6_neighbor_solicitation_header_t *h;
1891 ip6_address_t *src;
1892 ip_interface_address_t *ia;
1893 ip_adjacency_t *adj;
1894 vnet_hw_interface_t *hi;
1895 vnet_sw_interface_t *si;
1896 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001897 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001898 u32 bi = 0;
1899 int bogus_length;
1900
1901 si = vnet_get_sw_interface (vnm, sw_if_index);
1902
1903 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1904 {
1905 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001906 format_ip6_address, dst,
1907 format_vnet_sw_if_index_name, vnm,
1908 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001909 }
1910
Dave Barachd7cb1b52016-12-09 09:52:16 -05001911 src =
1912 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1913 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001914 {
1915 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001916 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 (0, "no matching interface address for destination %U (interface %U)",
1918 format_ip6_address, dst,
1919 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920 }
1921
Dave Barachd7cb1b52016-12-09 09:52:16 -05001922 h =
1923 vlib_packet_template_get_packet (vm,
1924 &im->discover_neighbor_packet_template,
1925 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926
1927 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1928
1929 /* Destination address is a solicited node multicast address. We need to fill in
1930 the low 24 bits with low 24 bits of target's address. */
1931 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1932 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1933 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1934
1935 h->ip.src_address = src[0];
1936 h->neighbor.target_address = dst[0];
1937
Pavel Kotucek57808982017-08-02 08:20:19 +02001938 if (PREDICT_FALSE (!hi->hw_address))
1939 {
1940 return clib_error_return (0, "%U: interface %U do not support ip probe",
1941 format_ip6_address, dst,
1942 format_vnet_sw_if_index_name, vnm,
1943 sw_if_index);
1944 }
1945
Dave Barachd7cb1b52016-12-09 09:52:16 -05001946 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1947 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948
Dave Barach75fc8542016-10-11 16:16:02 -04001949 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001950 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001951 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001952
1953 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001954 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1955 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956
1957 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07001958 ip46_address_t nh = {
1959 .ip6 = *dst,
1960 };
1961
1962 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
1963 VNET_LINK_IP6, &nh, sw_if_index);
1964 adj = adj_get (ai);
1965
Ed Warnickecb9cada2015-12-08 15:45:58 -07001966 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1967 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1968
1969 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001970 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1971 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001972 to_next[0] = bi;
1973 f->n_vectors = 1;
1974 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1975 }
1976
Neale Ranns7a272742017-05-30 02:08:14 -07001977 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001978 return /* no error */ 0;
1979}
1980
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981typedef enum
1982{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001984 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001985} ip6_rewrite_next_t;
1986
1987always_inline uword
1988ip6_rewrite_inline (vlib_main_t * vm,
1989 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001990 vlib_frame_t * frame,
1991 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1994 u32 *from = vlib_frame_vector_args (frame);
1995 u32 n_left_from, n_left_to_next, *to_next, next_index;
1996 vlib_node_runtime_t *error_node =
1997 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998
1999 n_left_from = frame->n_vectors;
2000 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002001 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002002
Ed Warnickecb9cada2015-12-08 15:45:58 -07002003 while (n_left_from > 0)
2004 {
2005 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2006
2007 while (n_left_from >= 4 && n_left_to_next >= 2)
2008 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002009 ip_adjacency_t *adj0, *adj1;
2010 vlib_buffer_t *p0, *p1;
2011 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012 u32 pi0, rw_len0, next0, error0, adj_index0;
2013 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002014 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04002015
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016 /* Prefetch next iteration. */
2017 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002018 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002019
2020 p2 = vlib_get_buffer (vm, from[2]);
2021 p3 = vlib_get_buffer (vm, from[3]);
2022
2023 vlib_prefetch_buffer_header (p2, LOAD);
2024 vlib_prefetch_buffer_header (p3, LOAD);
2025
2026 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2027 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2028
2029 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2030 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2031 }
2032
2033 pi0 = to_next[0] = from[0];
2034 pi1 = to_next[1] = from[1];
2035
2036 from += 2;
2037 n_left_from -= 2;
2038 to_next += 2;
2039 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002040
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041 p0 = vlib_get_buffer (vm, pi0);
2042 p1 = vlib_get_buffer (vm, pi1);
2043
Neale Rannsf06aea52016-11-29 06:51:37 -08002044 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2045 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046
Ed Warnickecb9cada2015-12-08 15:45:58 -07002047 ip0 = vlib_buffer_get_current (p0);
2048 ip1 = vlib_buffer_get_current (p1);
2049
2050 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002051 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002052
Damjan Marion213b5aa2017-07-13 21:19:27 +02002053 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002055 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002056
2057 /* Input node should have reject packets with hop limit 0. */
2058 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059
2060 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002061
2062 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002063
Dave Barachd7cb1b52016-12-09 09:52:16 -05002064 /*
2065 * If the hop count drops below 1 when forwarding, generate
2066 * an ICMP response.
2067 */
2068 if (PREDICT_FALSE (hop_limit0 <= 0))
2069 {
2070 error0 = IP6_ERROR_TIME_EXPIRED;
2071 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2072 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2073 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2074 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2075 0);
2076 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002077 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002078 else
2079 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002080 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002081 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002082 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002083 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002084 i32 hop_limit1 = ip1->hop_limit;
2085
2086 /* Input node should have reject packets with hop limit 0. */
2087 ASSERT (ip1->hop_limit > 0);
2088
2089 hop_limit1 -= 1;
2090
2091 ip1->hop_limit = hop_limit1;
2092
Dave Barachd7cb1b52016-12-09 09:52:16 -05002093 /*
2094 * If the hop count drops below 1 when forwarding, generate
2095 * an ICMP response.
2096 */
2097 if (PREDICT_FALSE (hop_limit1 <= 0))
2098 {
2099 error1 = IP6_ERROR_TIME_EXPIRED;
2100 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2101 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2102 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2103 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2104 0);
2105 }
2106 }
2107 else
2108 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002109 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002110 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002111 adj0 = adj_get (adj_index0);
2112 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113
Ed Warnickecb9cada2015-12-08 15:45:58 -07002114 rw_len0 = adj0[0].rewrite_header.data_bytes;
2115 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002116 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2117 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002118
Neale Ranns9c6a6132017-02-21 05:33:14 -08002119 if (do_counters)
2120 {
2121 vlib_increment_combined_counter
2122 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002123 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002124 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2125 vlib_increment_combined_counter
2126 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002127 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002128 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2129 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002130
2131 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002132 error0 =
2133 (vlib_buffer_length_in_chain (vm, p0) >
2134 adj0[0].
2135 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2136 error0);
2137 error1 =
2138 (vlib_buffer_length_in_chain (vm, p1) >
2139 adj1[0].
2140 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2141 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002142
Dave Barachd7cb1b52016-12-09 09:52:16 -05002143 /* Don't adjust the buffer for hop count issue; icmp-error node
2144 * wants to see the IP headerr */
2145 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2146 {
2147 p0->current_data -= rw_len0;
2148 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2151 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2152 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002153
Neale Rannsb069a692017-03-15 12:34:25 -04002154 if (PREDICT_FALSE
2155 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2156 vnet_feature_arc_start (lm->output_feature_arc_index,
2157 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002158 }
2159 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2160 {
2161 p1->current_data -= rw_len1;
2162 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2165 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2166 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002167
Neale Rannsb069a692017-03-15 12:34:25 -04002168 if (PREDICT_FALSE
2169 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2170 vnet_feature_arc_start (lm->output_feature_arc_index,
2171 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002172 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002173
2174 /* Guess we are only writing on simple Ethernet header. */
2175 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002176 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002177
Neale Ranns5e575b12016-10-03 09:40:25 +01002178 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002179 {
2180 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2181 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2182 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002183 if (is_mcast)
2184 {
2185 /*
2186 * copy bytes from the IP address into the MAC rewrite
2187 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002188 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2189 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002190 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002191
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2193 to_next, n_left_to_next,
2194 pi0, pi1, next0, next1);
2195 }
2196
2197 while (n_left_from > 0 && n_left_to_next > 0)
2198 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002199 ip_adjacency_t *adj0;
2200 vlib_buffer_t *p0;
2201 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202 u32 pi0, rw_len0;
2203 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002204 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002205
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206 pi0 = to_next[0] = from[0];
2207
2208 p0 = vlib_get_buffer (vm, pi0);
2209
Neale Rannsf06aea52016-11-29 06:51:37 -08002210 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002211
Neale Ranns107e7d42017-04-11 09:55:19 -07002212 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002213
Ed Warnickecb9cada2015-12-08 15:45:58 -07002214 ip0 = vlib_buffer_get_current (p0);
2215
2216 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002217 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002218
2219 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002220 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002221 {
2222 i32 hop_limit0 = ip0->hop_limit;
2223
2224 ASSERT (ip0->hop_limit > 0);
2225
2226 hop_limit0 -= 1;
2227
2228 ip0->hop_limit = hop_limit0;
2229
Dave Barachd7cb1b52016-12-09 09:52:16 -05002230 if (PREDICT_FALSE (hop_limit0 <= 0))
2231 {
2232 /*
2233 * If the hop count drops below 1 when forwarding, generate
2234 * an ICMP response.
2235 */
2236 error0 = IP6_ERROR_TIME_EXPIRED;
2237 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2238 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2239 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2240 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2241 0);
2242 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002244 else
2245 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002246 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249 /* Guess we are only writing on simple Ethernet header. */
2250 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002251
Ed Warnickecb9cada2015-12-08 15:45:58 -07002252 /* Update packet buffer attributes/set output interface. */
2253 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002254 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002255
Neale Ranns9c6a6132017-02-21 05:33:14 -08002256 if (do_counters)
2257 {
2258 vlib_increment_combined_counter
2259 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002260 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002261 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2262 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263
2264 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002265 error0 =
2266 (vlib_buffer_length_in_chain (vm, p0) >
2267 adj0[0].
2268 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2269 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270
Dave Barachd7cb1b52016-12-09 09:52:16 -05002271 /* Don't adjust the buffer for hop count issue; icmp-error node
2272 * wants to see the IP headerr */
2273 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2274 {
Chris Luke816f3e12016-06-14 16:24:47 -04002275 p0->current_data -= rw_len0;
2276 p0->current_length += rw_len0;
2277
Dave Barachd7cb1b52016-12-09 09:52:16 -05002278 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002279
Dave Barachd7cb1b52016-12-09 09:52:16 -05002280 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2281 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002282
Neale Rannsb069a692017-03-15 12:34:25 -04002283 if (PREDICT_FALSE
2284 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2285 vnet_feature_arc_start (lm->output_feature_arc_index,
2286 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002287 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002288
Neale Ranns5e575b12016-10-03 09:40:25 +01002289 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002290 {
2291 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2292 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002293 if (is_mcast)
2294 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002295 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002296 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002297
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298 p0->error = error_node->errors[error0];
2299
2300 from += 1;
2301 n_left_from -= 1;
2302 to_next += 1;
2303 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002304
Ed Warnickecb9cada2015-12-08 15:45:58 -07002305 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2306 to_next, n_left_to_next,
2307 pi0, next0);
2308 }
2309
2310 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2311 }
2312
2313 /* Need to do trace after rewrites to pick up new packet data. */
2314 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002315 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002316
2317 return frame->n_vectors;
2318}
2319
2320static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002321ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002322 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002324 if (adj_are_counters_enabled ())
2325 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2326 else
2327 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002328}
2329
2330static uword
2331ip6_rewrite_mcast (vlib_main_t * vm,
2332 vlib_node_runtime_t * node, vlib_frame_t * frame)
2333{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002334 if (adj_are_counters_enabled ())
2335 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2336 else
2337 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002338}
2339
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002340static uword
2341ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002342 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002343{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002344 if (adj_are_counters_enabled ())
2345 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2346 else
2347 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002348}
2349
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002350static uword
2351ip6_mcast_midchain (vlib_main_t * vm,
2352 vlib_node_runtime_t * node, vlib_frame_t * frame)
2353{
2354 if (adj_are_counters_enabled ())
2355 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2356 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002357 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002358}
2359
Dave Barachd7cb1b52016-12-09 09:52:16 -05002360/* *INDENT-OFF* */
2361VLIB_REGISTER_NODE (ip6_midchain_node) =
2362{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002363 .function = ip6_midchain,
2364 .name = "ip6-midchain",
2365 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002366 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002367 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002368 };
2369/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002370
Dave Barachd7cb1b52016-12-09 09:52:16 -05002371VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002372
Dave Barachd7cb1b52016-12-09 09:52:16 -05002373/* *INDENT-OFF* */
2374VLIB_REGISTER_NODE (ip6_rewrite_node) =
2375{
Neale Rannsf06aea52016-11-29 06:51:37 -08002376 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002377 .name = "ip6-rewrite",
2378 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002379 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002380 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002381 .next_nodes =
2382 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002384 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002385 },
2386};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002387/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002388
Neale Rannsf06aea52016-11-29 06:51:37 -08002389VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002390
Neale Ranns32e1c012016-11-22 17:07:28 +00002391/* *INDENT-OFF* */
2392VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2393{
2394 .function = ip6_rewrite_mcast,
2395 .name = "ip6-rewrite-mcast",
2396 .vector_size = sizeof (u32),
2397 .format_trace = format_ip6_rewrite_trace,
2398 .sibling_of = "ip6-rewrite",
2399};
2400/* *INDENT-ON* */
2401
2402VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2403
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002404/* *INDENT-OFF* */
2405VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2406{
2407 .function = ip6_mcast_midchain,
2408 .name = "ip6-mcast-midchain",
2409 .vector_size = sizeof (u32),
2410 .format_trace = format_ip6_rewrite_trace,
2411 .sibling_of = "ip6-rewrite",
2412};
2413/* *INDENT-ON* */
2414
2415VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2416
Ole Troan944f5482016-05-24 11:56:58 +02002417/*
2418 * Hop-by-Hop handling
2419 */
Ole Troan944f5482016-05-24 11:56:58 +02002420ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2421
2422#define foreach_ip6_hop_by_hop_error \
2423_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2424_(FORMAT, "incorrectly formatted hop-by-hop options") \
2425_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2426
Neale Ranns32e1c012016-11-22 17:07:28 +00002427/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428typedef enum
2429{
Ole Troan944f5482016-05-24 11:56:58 +02002430#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2431 foreach_ip6_hop_by_hop_error
2432#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002433 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002434} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002435/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002436
2437/*
2438 * Primary h-b-h handler trace support
2439 * We work pretty hard on the problem for obvious reasons
2440 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002441typedef struct
2442{
Ole Troan944f5482016-05-24 11:56:58 +02002443 u32 next_index;
2444 u32 trace_len;
2445 u8 option_data[256];
2446} ip6_hop_by_hop_trace_t;
2447
2448vlib_node_registration_t ip6_hop_by_hop_node;
2449
Dave Barachd7cb1b52016-12-09 09:52:16 -05002450static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002451#define _(sym,string) string,
2452 foreach_ip6_hop_by_hop_error
2453#undef _
2454};
2455
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302456u8 *
2457format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2458{
2459 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2460 int total_len = va_arg (*args, int);
2461 ip6_hop_by_hop_option_t *opt0, *limit0;
2462 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2463 u8 type0;
2464
2465 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2466 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2467
2468 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2469 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2470
2471 while (opt0 < limit0)
2472 {
2473 type0 = opt0->type;
2474 switch (type0)
2475 {
2476 case 0: /* Pad, just stop */
2477 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2478 break;
2479
2480 default:
2481 if (hm->trace[type0])
2482 {
2483 s = (*hm->trace[type0]) (s, opt0);
2484 }
2485 else
2486 {
2487 s =
2488 format (s, "\n unrecognized option %d length %d", type0,
2489 opt0->length);
2490 }
2491 opt0 =
2492 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2493 sizeof (ip6_hop_by_hop_option_t));
2494 break;
2495 }
2496 }
2497 return s;
2498}
2499
Ole Troan944f5482016-05-24 11:56:58 +02002500static u8 *
2501format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2502{
2503 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2504 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002506 ip6_hop_by_hop_header_t *hbh0;
2507 ip6_hop_by_hop_option_t *opt0, *limit0;
2508 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2509
2510 u8 type0;
2511
Dave Barachd7cb1b52016-12-09 09:52:16 -05002512 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002513
2514 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002515 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002516
Dave Barachd7cb1b52016-12-09 09:52:16 -05002517 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2518 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002519
Dave Barachd7cb1b52016-12-09 09:52:16 -05002520 while (opt0 < limit0)
2521 {
2522 type0 = opt0->type;
2523 switch (type0)
2524 {
2525 case 0: /* Pad, just stop */
2526 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2527 break;
Ole Troan944f5482016-05-24 11:56:58 +02002528
Dave Barachd7cb1b52016-12-09 09:52:16 -05002529 default:
2530 if (hm->trace[type0])
2531 {
2532 s = (*hm->trace[type0]) (s, opt0);
2533 }
2534 else
2535 {
2536 s =
2537 format (s, "\n unrecognized option %d length %d", type0,
2538 opt0->length);
2539 }
2540 opt0 =
2541 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2542 sizeof (ip6_hop_by_hop_option_t));
2543 break;
2544 }
Ole Troan944f5482016-05-24 11:56:58 +02002545 }
Ole Troan944f5482016-05-24 11:56:58 +02002546 return s;
2547}
2548
Dave Barachd7cb1b52016-12-09 09:52:16 -05002549always_inline u8
2550ip6_scan_hbh_options (vlib_buffer_t * b0,
2551 ip6_header_t * ip0,
2552 ip6_hop_by_hop_header_t * hbh0,
2553 ip6_hop_by_hop_option_t * opt0,
2554 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002555{
2556 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2557 u8 type0;
2558 u8 error0 = 0;
2559
2560 while (opt0 < limit0)
2561 {
2562 type0 = opt0->type;
2563 switch (type0)
2564 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002565 case 0: /* Pad1 */
2566 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002567 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002568 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002569 break;
2570 default:
2571 if (hm->options[type0])
2572 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002573 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2574 {
Shwethaa91cbe62016-08-08 15:51:04 +01002575 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002576 return (error0);
2577 }
Shwethaa91cbe62016-08-08 15:51:04 +01002578 }
2579 else
2580 {
2581 /* Unrecognized mandatory option, check the two high order bits */
2582 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2583 {
2584 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2585 break;
2586 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2587 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2588 *next0 = IP_LOOKUP_NEXT_DROP;
2589 break;
2590 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2591 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2592 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002593 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2594 ICMP6_parameter_problem_unrecognized_option,
2595 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002596 break;
2597 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2598 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002599 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002600 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002601 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2602 icmp6_error_set_vnet_buffer (b0,
2603 ICMP6_parameter_problem,
2604 ICMP6_parameter_problem_unrecognized_option,
2605 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002606 }
2607 else
2608 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002609 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002610 }
2611 break;
2612 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002613 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002614 }
2615 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002616 opt0 =
2617 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2618 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002619 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002621}
2622
Ole Troan944f5482016-05-24 11:56:58 +02002623/*
2624 * Process the Hop-by-Hop Options header
2625 */
2626static uword
2627ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002628 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002629{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002630 vlib_node_runtime_t *error_node =
2631 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002632 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2633 u32 n_left_from, *from, *to_next;
2634 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002635
2636 from = vlib_frame_vector_args (frame);
2637 n_left_from = frame->n_vectors;
2638 next_index = node->cached_next_index;
2639
Dave Barachd7cb1b52016-12-09 09:52:16 -05002640 while (n_left_from > 0)
2641 {
2642 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002643
Dave Barachd7cb1b52016-12-09 09:52:16 -05002644 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002645
Dave Barachd7cb1b52016-12-09 09:52:16 -05002646 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002647 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002648 u32 bi0, bi1;
2649 vlib_buffer_t *b0, *b1;
2650 u32 next0, next1;
2651 ip6_header_t *ip0, *ip1;
2652 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2653 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2654 u8 error0 = 0, error1 = 0;
2655
2656 /* Prefetch next iteration. */
2657 {
2658 vlib_buffer_t *p2, *p3;
2659
2660 p2 = vlib_get_buffer (vm, from[2]);
2661 p3 = vlib_get_buffer (vm, from[3]);
2662
2663 vlib_prefetch_buffer_header (p2, LOAD);
2664 vlib_prefetch_buffer_header (p3, LOAD);
2665
2666 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2667 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002668 }
2669
Dave Barachd7cb1b52016-12-09 09:52:16 -05002670 /* Speculatively enqueue b0, b1 to the current next frame */
2671 to_next[0] = bi0 = from[0];
2672 to_next[1] = bi1 = from[1];
2673 from += 2;
2674 to_next += 2;
2675 n_left_from -= 2;
2676 n_left_to_next -= 2;
2677
2678 b0 = vlib_get_buffer (vm, bi0);
2679 b1 = vlib_get_buffer (vm, bi1);
2680
2681 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2682 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002683 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002684 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002685 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002686
2687 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2688 next0 = adj0->lookup_next_index;
2689 next1 = adj1->lookup_next_index;
2690
2691 ip0 = vlib_buffer_get_current (b0);
2692 ip1 = vlib_buffer_get_current (b1);
2693 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2694 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2695 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2696 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2697 limit0 =
2698 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2699 ((hbh0->length + 1) << 3));
2700 limit1 =
2701 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2702 ((hbh1->length + 1) << 3));
2703
2704 /*
2705 * Basic validity checks
2706 */
2707 if ((hbh0->length + 1) << 3 >
2708 clib_net_to_host_u16 (ip0->payload_length))
2709 {
2710 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2711 next0 = IP_LOOKUP_NEXT_DROP;
2712 goto outdual;
2713 }
2714 /* Scan the set of h-b-h options, process ones that we understand */
2715 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2716
2717 if ((hbh1->length + 1) << 3 >
2718 clib_net_to_host_u16 (ip1->payload_length))
2719 {
2720 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2721 next1 = IP_LOOKUP_NEXT_DROP;
2722 goto outdual;
2723 }
2724 /* Scan the set of h-b-h options, process ones that we understand */
2725 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2726
2727 outdual:
2728 /* Has the classifier flagged this buffer for special treatment? */
2729 if (PREDICT_FALSE
2730 ((error0 == 0)
2731 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2732 next0 = hm->next_override;
2733
2734 /* Has the classifier flagged this buffer for special treatment? */
2735 if (PREDICT_FALSE
2736 ((error1 == 0)
2737 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2738 next1 = hm->next_override;
2739
2740 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2741 {
2742 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2743 {
2744 ip6_hop_by_hop_trace_t *t =
2745 vlib_add_trace (vm, node, b0, sizeof (*t));
2746 u32 trace_len = (hbh0->length + 1) << 3;
2747 t->next_index = next0;
2748 /* Capture the h-b-h option verbatim */
2749 trace_len =
2750 trace_len <
2751 ARRAY_LEN (t->option_data) ? trace_len :
2752 ARRAY_LEN (t->option_data);
2753 t->trace_len = trace_len;
2754 clib_memcpy (t->option_data, hbh0, trace_len);
2755 }
2756 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2757 {
2758 ip6_hop_by_hop_trace_t *t =
2759 vlib_add_trace (vm, node, b1, sizeof (*t));
2760 u32 trace_len = (hbh1->length + 1) << 3;
2761 t->next_index = next1;
2762 /* Capture the h-b-h option verbatim */
2763 trace_len =
2764 trace_len <
2765 ARRAY_LEN (t->option_data) ? trace_len :
2766 ARRAY_LEN (t->option_data);
2767 t->trace_len = trace_len;
2768 clib_memcpy (t->option_data, hbh1, trace_len);
2769 }
2770
2771 }
2772
2773 b0->error = error_node->errors[error0];
2774 b1->error = error_node->errors[error1];
2775
2776 /* verify speculative enqueue, maybe switch current next frame */
2777 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2778 n_left_to_next, bi0, bi1, next0,
2779 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002780 }
2781
Dave Barachd7cb1b52016-12-09 09:52:16 -05002782 while (n_left_from > 0 && n_left_to_next > 0)
2783 {
2784 u32 bi0;
2785 vlib_buffer_t *b0;
2786 u32 next0;
2787 ip6_header_t *ip0;
2788 ip6_hop_by_hop_header_t *hbh0;
2789 ip6_hop_by_hop_option_t *opt0, *limit0;
2790 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002791
Dave Barachd7cb1b52016-12-09 09:52:16 -05002792 /* Speculatively enqueue b0 to the current next frame */
2793 bi0 = from[0];
2794 to_next[0] = bi0;
2795 from += 1;
2796 to_next += 1;
2797 n_left_from -= 1;
2798 n_left_to_next -= 1;
2799
2800 b0 = vlib_get_buffer (vm, bi0);
2801 /*
2802 * Default use the next_index from the adjacency.
2803 * A HBH option rarely redirects to a different node
2804 */
2805 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002806 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002807 next0 = adj0->lookup_next_index;
2808
2809 ip0 = vlib_buffer_get_current (b0);
2810 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2811 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2812 limit0 =
2813 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2814 ((hbh0->length + 1) << 3));
2815
2816 /*
2817 * Basic validity checks
2818 */
2819 if ((hbh0->length + 1) << 3 >
2820 clib_net_to_host_u16 (ip0->payload_length))
2821 {
2822 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2823 next0 = IP_LOOKUP_NEXT_DROP;
2824 goto out0;
2825 }
2826
2827 /* Scan the set of h-b-h options, process ones that we understand */
2828 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2829
2830 out0:
2831 /* Has the classifier flagged this buffer for special treatment? */
2832 if (PREDICT_FALSE
2833 ((error0 == 0)
2834 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2835 next0 = hm->next_override;
2836
2837 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2838 {
2839 ip6_hop_by_hop_trace_t *t =
2840 vlib_add_trace (vm, node, b0, sizeof (*t));
2841 u32 trace_len = (hbh0->length + 1) << 3;
2842 t->next_index = next0;
2843 /* Capture the h-b-h option verbatim */
2844 trace_len =
2845 trace_len <
2846 ARRAY_LEN (t->option_data) ? trace_len :
2847 ARRAY_LEN (t->option_data);
2848 t->trace_len = trace_len;
2849 clib_memcpy (t->option_data, hbh0, trace_len);
2850 }
2851
2852 b0->error = error_node->errors[error0];
2853
2854 /* verify speculative enqueue, maybe switch current next frame */
2855 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2856 n_left_to_next, bi0, next0);
2857 }
2858 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002859 }
Ole Troan944f5482016-05-24 11:56:58 +02002860 return frame->n_vectors;
2861}
2862
Dave Barachd7cb1b52016-12-09 09:52:16 -05002863/* *INDENT-OFF* */
2864VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2865{
Ole Troan944f5482016-05-24 11:56:58 +02002866 .function = ip6_hop_by_hop,
2867 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002868 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002869 .vector_size = sizeof (u32),
2870 .format_trace = format_ip6_hop_by_hop_trace,
2871 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002872 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002873 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002874 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002875};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002876/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002877
Dave Barach5331c722016-08-17 11:54:30 -04002878VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002879
2880static clib_error_t *
2881ip6_hop_by_hop_init (vlib_main_t * vm)
2882{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002883 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2884 memset (hm->options, 0, sizeof (hm->options));
2885 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002886 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002887 return (0);
2888}
2889
2890VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2891
Dave Barachd7cb1b52016-12-09 09:52:16 -05002892void
2893ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002894{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002895 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002896
2897 hm->next_override = next;
2898}
2899
Ole Troan944f5482016-05-24 11:56:58 +02002900int
2901ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002902 int options (vlib_buffer_t * b, ip6_header_t * ip,
2903 ip6_hop_by_hop_option_t * opt),
2904 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002905{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002906 ip6_main_t *im = &ip6_main;
2907 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002908
2909 ASSERT (option < ARRAY_LEN (hm->options));
2910
2911 /* Already registered */
2912 if (hm->options[option])
2913 return (-1);
2914
2915 hm->options[option] = options;
2916 hm->trace[option] = trace;
2917
2918 /* Set global variable */
2919 im->hbh_enabled = 1;
2920
2921 return (0);
2922}
2923
2924int
2925ip6_hbh_unregister_option (u8 option)
2926{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002927 ip6_main_t *im = &ip6_main;
2928 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002929
2930 ASSERT (option < ARRAY_LEN (hm->options));
2931
2932 /* Not registered */
2933 if (!hm->options[option])
2934 return (-1);
2935
2936 hm->options[option] = NULL;
2937 hm->trace[option] = NULL;
2938
2939 /* Disable global knob if this was the last option configured */
2940 int i;
2941 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002942 for (i = 0; i < 256; i++)
2943 {
2944 if (hm->options[option])
2945 {
2946 found = true;
2947 break;
2948 }
Ole Troan944f5482016-05-24 11:56:58 +02002949 }
Ole Troan944f5482016-05-24 11:56:58 +02002950 if (!found)
2951 im->hbh_enabled = 0;
2952
2953 return (0);
2954}
2955
Ed Warnickecb9cada2015-12-08 15:45:58 -07002956/* Global IP6 main. */
2957ip6_main_t ip6_main;
2958
2959static clib_error_t *
2960ip6_lookup_init (vlib_main_t * vm)
2961{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962 ip6_main_t *im = &ip6_main;
2963 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002964 uword i;
2965
Damjan Marion8b3191e2016-11-09 19:54:20 +01002966 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2967 return error;
2968
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2970 {
2971 u32 j, i0, i1;
2972
2973 i0 = i / 32;
2974 i1 = i % 32;
2975
2976 for (j = 0; j < i0; j++)
2977 im->fib_masks[i].as_u32[j] = ~0;
2978
2979 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002980 im->fib_masks[i].as_u32[i0] =
2981 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002982 }
2983
2984 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2985
2986 if (im->lookup_table_nbuckets == 0)
2987 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2988
Dave Barachd7cb1b52016-12-09 09:52:16 -05002989 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002990
2991 if (im->lookup_table_size == 0)
2992 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002993
Dave Barachd7cb1b52016-12-09 09:52:16 -05002994 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2995 "ip6 FIB fwding table",
2996 im->lookup_table_nbuckets, im->lookup_table_size);
2997 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2998 "ip6 FIB non-fwding table",
2999 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003000
Ed Warnickecb9cada2015-12-08 15:45:58 -07003001 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003002 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00003003 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003004
3005 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003006 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003007 pn = pg_get_node (ip6_lookup_node.index);
3008 pn->unformat_edit = unformat_pg_ip6_header;
3009 }
3010
Ole Troan944f5482016-05-24 11:56:58 +02003011 /* Unless explicitly configured, don't process HBH options */
3012 im->hbh_enabled = 0;
3013
Ed Warnickecb9cada2015-12-08 15:45:58 -07003014 {
3015 icmp6_neighbor_solicitation_header_t p;
3016
3017 memset (&p, 0, sizeof (p));
3018
Dave Barachd7cb1b52016-12-09 09:52:16 -05003019 p.ip.ip_version_traffic_class_and_flow_label =
3020 clib_host_to_net_u32 (0x6 << 28);
3021 p.ip.payload_length =
3022 clib_host_to_net_u16 (sizeof (p) -
3023 STRUCT_OFFSET_OF
3024 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025 p.ip.protocol = IP_PROTOCOL_ICMP6;
3026 p.ip.hop_limit = 255;
3027 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3028
3029 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3030
Dave Barachd7cb1b52016-12-09 09:52:16 -05003031 p.link_layer_option.header.type =
3032 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3033 p.link_layer_option.header.n_data_u64s =
3034 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003035
3036 vlib_packet_template_init (vm,
3037 &im->discover_neighbor_packet_template,
3038 &p, sizeof (p),
3039 /* alloc chunk size */ 8,
3040 "ip6 neighbor discovery");
3041 }
3042
Dave Barach203c6322016-06-26 10:29:03 -04003043 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003044}
3045
3046VLIB_INIT_FUNCTION (ip6_lookup_init);
3047
3048static clib_error_t *
3049add_del_ip6_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003050 unformat_input_t * input,
3051 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003053 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08003054 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003055 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003056 u32 sw_if_index, table_id;
3057
3058 sw_if_index = ~0;
3059
Dave Barachd7cb1b52016-12-09 09:52:16 -05003060 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061 {
3062 error = clib_error_return (0, "unknown interface `%U'",
3063 format_unformat_error, input);
3064 goto done;
3065 }
3066
3067 if (unformat (input, "%d", &table_id))
3068 ;
3069 else
3070 {
3071 error = clib_error_return (0, "expected table id `%U'",
3072 format_unformat_error, input);
3073 goto done;
3074 }
3075
Neale Ranns4008ac92017-02-13 23:20:04 -08003076 /*
3077 * If the interface already has in IP address, then a change int
3078 * VRF is not allowed. The IP address applied must first be removed.
3079 * We do not do that automatically here, since VPP has no knowledge
3080 * of whether thoses subnets are valid in the destination VRF.
3081 */
3082 /* *INDENT-OFF* */
3083 foreach_ip_interface_address (&ip6_main.lookup_main,
3084 ia, sw_if_index,
3085 1 /* honor unnumbered */,
3086 ({
3087 ip4_address_t * a;
3088
3089 a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
3090 error = clib_error_return (0, "interface %U has address %U",
3091 format_vnet_sw_if_index_name, vnm,
3092 sw_if_index,
3093 format_ip6_address, a);
3094 goto done;
3095 }));
3096 /* *INDENT-ON* */
3097
Ed Warnickecb9cada2015-12-08 15:45:58 -07003098 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003099 u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3100 table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003101
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003102 vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
3103 ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00003104
3105 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3106 table_id);
3107
3108 vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
3109 ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003110 }
3111
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003112
Dave Barachd7cb1b52016-12-09 09:52:16 -05003113done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003114 return error;
3115}
3116
Billy McFall0683c9c2016-10-13 08:27:31 -04003117/*?
3118 * Place the indicated interface into the supplied IPv6 FIB table (also known
3119 * as a VRF). If the FIB table does not exist, this command creates it. To
3120 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3121 * FIB table will only be displayed if a route has been added to the table, or
3122 * an IP Address is assigned to an interface in the table (which adds a route
3123 * automatically).
3124 *
Neale Ranns4008ac92017-02-13 23:20:04 -08003125 * @note IP addresses added after setting the interface IP table are added to
3126 * the indicated FIB table. If an IP address is added prior to changing the
3127 * table then this is an error. The control plane must remove these addresses
3128 * first and then change the table. VPP will not automatically move the
3129 * addresses from the old to the new table as it does not know the validity
3130 * of such a change.
Billy McFall0683c9c2016-10-13 08:27:31 -04003131 *
3132 * @cliexpar
3133 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3134 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3135 ?*/
3136/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003137VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3138{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139 .path = "set interface ip6 table",
3140 .function = add_del_ip6_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04003141 .short_help = "set interface ip6 table <interface> <table-id>"
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142};
Billy McFall0683c9c2016-10-13 08:27:31 -04003143/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003144
Dave Barach75fc8542016-10-11 16:16:02 -04003145void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003146ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3147 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003148{
3149 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3150 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003151 ip->as_u8[8] = mac[0] ^ (1 << 1);
3152 ip->as_u8[9] = mac[1];
3153 ip->as_u8[10] = mac[2];
3154 ip->as_u8[11] = 0xFF;
3155 ip->as_u8[12] = 0xFE;
3156 ip->as_u8[13] = mac[3];
3157 ip->as_u8[14] = mac[4];
3158 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003159}
3160
Dave Barach75fc8542016-10-11 16:16:02 -04003161void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003162ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3163 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003164{
3165 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003166 mac[0] = ip->as_u8[8] ^ (1 << 1);
3167 mac[1] = ip->as_u8[9];
3168 mac[2] = ip->as_u8[10];
3169 mac[3] = ip->as_u8[13];
3170 mac[4] = ip->as_u8[14];
3171 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172}
3173
Dave Barach75fc8542016-10-11 16:16:02 -04003174static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003176 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003177{
3178 u8 mac[6];
3179 ip6_address_t _a, *a = &_a;
3180
3181 if (unformat (input, "%U", unformat_ethernet_address, mac))
3182 {
3183 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003184 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003185 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3186 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003187 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003188 }
Dave Barach75fc8542016-10-11 16:16:02 -04003189
Ed Warnickecb9cada2015-12-08 15:45:58 -07003190 return 0;
3191}
3192
Billy McFall0683c9c2016-10-13 08:27:31 -04003193/*?
3194 * This command converts the given MAC Address into an IPv6 link-local
3195 * address.
3196 *
3197 * @cliexpar
3198 * Example of how to create an IPv6 link-local address:
3199 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3200 * Link local address: fe80::14d9:e0ff:fe91:7986
3201 * Original MAC address: 16:d9:e0:91:79:86
3202 * @cliexend
3203?*/
3204/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003205VLIB_CLI_COMMAND (test_link_command, static) =
3206{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003207 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003208 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003209 .short_help = "test ip6 link <mac-address>",
3210};
Billy McFall0683c9c2016-10-13 08:27:31 -04003211/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003212
Dave Barachd7cb1b52016-12-09 09:52:16 -05003213int
3214vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003215{
Neale Ranns107e7d42017-04-11 09:55:19 -07003216 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217
Neale Ranns107e7d42017-04-11 09:55:19 -07003218 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003219
Neale Ranns107e7d42017-04-11 09:55:19 -07003220 if (~0 == fib_index)
3221 return VNET_API_ERROR_NO_SUCH_FIB;
3222
Neale Ranns227038a2017-04-21 01:07:59 -07003223 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3224 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003225
Neale Ranns227038a2017-04-21 01:07:59 -07003226 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003227}
3228
3229static clib_error_t *
3230set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003231 unformat_input_t * input,
3232 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003233{
3234 int matched = 0;
3235 u32 table_id = 0;
3236 u32 flow_hash_config = 0;
3237 int rv;
3238
Dave Barachd7cb1b52016-12-09 09:52:16 -05003239 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3240 {
3241 if (unformat (input, "table %d", &table_id))
3242 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003243#define _(a,v) \
3244 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003245 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003246#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003247 else
3248 break;
3249 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003250
3251 if (matched == 0)
3252 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003253 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003254
Ed Warnickecb9cada2015-12-08 15:45:58 -07003255 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3256 switch (rv)
3257 {
Neale Ranns227038a2017-04-21 01:07:59 -07003258 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003259 break;
3260
3261 case -1:
3262 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003263
Ed Warnickecb9cada2015-12-08 15:45:58 -07003264 default:
3265 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3266 break;
3267 }
Dave Barach75fc8542016-10-11 16:16:02 -04003268
Ed Warnickecb9cada2015-12-08 15:45:58 -07003269 return 0;
3270}
3271
Billy McFall0683c9c2016-10-13 08:27:31 -04003272/*?
3273 * Configure the set of IPv6 fields used by the flow hash.
3274 *
3275 * @cliexpar
3276 * @parblock
3277 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003278 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3279 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003280 * Example of display the configured flow hash:
3281 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003282 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3283 * @::/0
3284 * unicast-ip6-chain
3285 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3286 * [0] [@0]: dpo-drop ip6
3287 * fe80::/10
3288 * unicast-ip6-chain
3289 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3290 * [0] [@2]: dpo-receive
3291 * ff02::1/128
3292 * unicast-ip6-chain
3293 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3294 * [0] [@2]: dpo-receive
3295 * ff02::2/128
3296 * unicast-ip6-chain
3297 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3298 * [0] [@2]: dpo-receive
3299 * ff02::16/128
3300 * unicast-ip6-chain
3301 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3302 * [0] [@2]: dpo-receive
3303 * ff02::1:ff00:0/104
3304 * unicast-ip6-chain
3305 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3306 * [0] [@2]: dpo-receive
3307 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3308 * @::/0
3309 * unicast-ip6-chain
3310 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3311 * [0] [@0]: dpo-drop ip6
3312 * @::a:1:1:0:4/126
3313 * unicast-ip6-chain
3314 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3315 * [0] [@4]: ipv6-glean: af_packet0
3316 * @::a:1:1:0:7/128
3317 * unicast-ip6-chain
3318 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3319 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3320 * fe80::/10
3321 * unicast-ip6-chain
3322 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3323 * [0] [@2]: dpo-receive
3324 * fe80::fe:3eff:fe3e:9222/128
3325 * unicast-ip6-chain
3326 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3327 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3328 * ff02::1/128
3329 * unicast-ip6-chain
3330 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3331 * [0] [@2]: dpo-receive
3332 * ff02::2/128
3333 * unicast-ip6-chain
3334 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3335 * [0] [@2]: dpo-receive
3336 * ff02::16/128
3337 * unicast-ip6-chain
3338 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3339 * [0] [@2]: dpo-receive
3340 * ff02::1:ff00:0/104
3341 * unicast-ip6-chain
3342 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3343 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003344 * @cliexend
3345 * @endparblock
3346?*/
3347/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003348VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3349{
3350 .path = "set ip6 flow-hash",
3351 .short_help =
3352 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3353 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003354};
Billy McFall0683c9c2016-10-13 08:27:31 -04003355/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003356
3357static clib_error_t *
3358show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003359 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003360{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003361 ip6_main_t *im = &ip6_main;
3362 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003363 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003364
Ed Warnickecb9cada2015-12-08 15:45:58 -07003365 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003366 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003367 {
3368 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003369 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003370 }
3371 return 0;
3372}
3373
3374
3375
Billy McFall0683c9c2016-10-13 08:27:31 -04003376/*?
3377 * Display the set of protocols handled by the local IPv6 stack.
3378 *
3379 * @cliexpar
3380 * Example of how to display local protocol table:
3381 * @cliexstart{show ip6 local}
3382 * Protocols handled by ip6_local
3383 * 17
3384 * 43
3385 * 58
3386 * 115
3387 * @cliexend
3388?*/
3389/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003390VLIB_CLI_COMMAND (show_ip6_local, static) =
3391{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003392 .path = "show ip6 local",
3393 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003394 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003395};
Billy McFall0683c9c2016-10-13 08:27:31 -04003396/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003397
Dave Barachd7cb1b52016-12-09 09:52:16 -05003398int
3399vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3400 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003401{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003402 vnet_main_t *vnm = vnet_get_main ();
3403 vnet_interface_main_t *im = &vnm->interface_main;
3404 ip6_main_t *ipm = &ip6_main;
3405 ip_lookup_main_t *lm = &ipm->lookup_main;
3406 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003407 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003408
3409 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3410 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3411
3412 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3413 return VNET_API_ERROR_NO_SUCH_ENTRY;
3414
3415 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003416 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003417
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003418 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003419
3420 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003421 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003422 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003423 .fp_len = 128,
3424 .fp_proto = FIB_PROTOCOL_IP6,
3425 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003426 };
3427 u32 fib_index;
3428
Dave Barachd7cb1b52016-12-09 09:52:16 -05003429 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3430 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003431
3432
Dave Barachd7cb1b52016-12-09 09:52:16 -05003433 if (table_index != (u32) ~ 0)
3434 {
3435 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003436
Dave Barachd7cb1b52016-12-09 09:52:16 -05003437 dpo_set (&dpo,
3438 DPO_CLASSIFY,
3439 DPO_PROTO_IP6,
3440 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003441
Dave Barachd7cb1b52016-12-09 09:52:16 -05003442 fib_table_entry_special_dpo_add (fib_index,
3443 &pfx,
3444 FIB_SOURCE_CLASSIFY,
3445 FIB_ENTRY_FLAG_NONE, &dpo);
3446 dpo_reset (&dpo);
3447 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003448 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003449 {
3450 fib_table_entry_special_remove (fib_index,
3451 &pfx, FIB_SOURCE_CLASSIFY);
3452 }
3453 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003454
Ed Warnickecb9cada2015-12-08 15:45:58 -07003455 return 0;
3456}
3457
3458static clib_error_t *
3459set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003460 unformat_input_t * input,
3461 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003462{
3463 u32 table_index = ~0;
3464 int table_index_set = 0;
3465 u32 sw_if_index = ~0;
3466 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003467
Dave Barachd7cb1b52016-12-09 09:52:16 -05003468 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3469 {
3470 if (unformat (input, "table-index %d", &table_index))
3471 table_index_set = 1;
3472 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3473 vnet_get_main (), &sw_if_index))
3474 ;
3475 else
3476 break;
3477 }
Dave Barach75fc8542016-10-11 16:16:02 -04003478
Ed Warnickecb9cada2015-12-08 15:45:58 -07003479 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003480 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003481
Ed Warnickecb9cada2015-12-08 15:45:58 -07003482 if (sw_if_index == ~0)
3483 return clib_error_return (0, "interface / subif must be specified");
3484
3485 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3486
3487 switch (rv)
3488 {
3489 case 0:
3490 break;
3491
3492 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3493 return clib_error_return (0, "No such interface");
3494
3495 case VNET_API_ERROR_NO_SUCH_ENTRY:
3496 return clib_error_return (0, "No such classifier table");
3497 }
3498 return 0;
3499}
3500
Billy McFall0683c9c2016-10-13 08:27:31 -04003501/*?
3502 * Assign a classification table to an interface. The classification
3503 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3504 * commands. Once the table is create, use this command to filter packets
3505 * on an interface.
3506 *
3507 * @cliexpar
3508 * Example of how to assign a classification table to an interface:
3509 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3510?*/
3511/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003512VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3513{
3514 .path = "set ip6 classify",
3515 .short_help =
3516 "set ip6 classify intfc <interface> table-index <classify-idx>",
3517 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003518};
Billy McFall0683c9c2016-10-13 08:27:31 -04003519/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003520
3521static clib_error_t *
3522ip6_config (vlib_main_t * vm, unformat_input_t * input)
3523{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003524 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003525 uword heapsize = 0;
3526 u32 tmp;
3527 u32 nbuckets = 0;
3528
Dave Barachd7cb1b52016-12-09 09:52:16 -05003529 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3530 {
3531 if (unformat (input, "hash-buckets %d", &tmp))
3532 nbuckets = tmp;
3533 else if (unformat (input, "heap-size %dm", &tmp))
3534 heapsize = ((u64) tmp) << 20;
3535 else if (unformat (input, "heap-size %dM", &tmp))
3536 heapsize = ((u64) tmp) << 20;
3537 else if (unformat (input, "heap-size %dg", &tmp))
3538 heapsize = ((u64) tmp) << 30;
3539 else if (unformat (input, "heap-size %dG", &tmp))
3540 heapsize = ((u64) tmp) << 30;
3541 else
3542 return clib_error_return (0, "unknown input '%U'",
3543 format_unformat_error, input);
3544 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003545
3546 im->lookup_table_nbuckets = nbuckets;
3547 im->lookup_table_size = heapsize;
3548
3549 return 0;
3550}
3551
3552VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003553
3554/*
3555 * fd.io coding-style-patch-verification: ON
3556 *
3557 * Local Variables:
3558 * eval: (c-set-style "gnu")
3559 * End:
3560 */