blob: 3bc07d0e679bbc979a6502caaed1c24e1a780e50 [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>
Dave Barachd7cb1b52016-12-09 09:52:16 -050042#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
44#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053045#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010046#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000047#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070048#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010049#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070050
51#include <vppinfra/bihash_template.c>
52
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053053/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
54#define OI_DECAP 0x80000000
55
Billy McFall0683c9c2016-10-13 08:27:31 -040056/**
57 * @file
58 * @brief IPv6 Forwarding.
59 *
60 * This file contains the source code for IPv6 forwarding.
61 */
62
Pierre Pfister0febaf12016-06-08 12:23:21 +010063void
64ip6_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050065 vlib_node_runtime_t * node,
66 vlib_frame_t * frame,
67 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010068
Damjan Marionaca64c92016-04-13 09:48:56 +020069always_inline uword
70ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050071 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
Dave Barachd7cb1b52016-12-09 09:52:16 -050073 ip6_main_t *im = &ip6_main;
74 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
75 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070076 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020077 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
79 from = vlib_frame_vector_args (frame);
80 n_left_from = frame->n_vectors;
81 next = node->cached_next_index;
82
83 while (n_left_from > 0)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
87 while (n_left_from >= 4 && n_left_to_next >= 2)
88 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050089 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050092 ip6_header_t *ip0, *ip1;
93 ip6_address_t *dst_addr0, *dst_addr1;
94 u32 fib_index0, fib_index1;
95 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010096 const dpo_id_t *dpo0, *dpo1;
97 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 /* Prefetch next iteration. */
100 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102
103 p2 = vlib_get_buffer (vm, from[2]);
104 p3 = vlib_get_buffer (vm, from[3]);
105
106 vlib_prefetch_buffer_header (p2, LOAD);
107 vlib_prefetch_buffer_header (p3, LOAD);
108 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
109 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
110 }
111
112 pi0 = to_next[0] = from[0];
113 pi1 = to_next[1] = from[1];
114
115 p0 = vlib_get_buffer (vm, pi0);
116 p1 = vlib_get_buffer (vm, pi1);
117
118 ip0 = vlib_buffer_get_current (p0);
119 ip1 = vlib_buffer_get_current (p1);
120
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121 dst_addr0 = &ip0->dst_address;
122 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200123
Dave Barachd7cb1b52016-12-09 09:52:16 -0500124 fib_index0 =
125 vec_elt (im->fib_index_by_sw_if_index,
126 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
127 fib_index1 =
128 vec_elt (im->fib_index_by_sw_if_index,
129 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
132 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
133 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
134 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100136 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
137 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100139 lb0 = load_balance_get (lbi0);
140 lb1 = load_balance_get (lbi1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700141 ASSERT (lb0->lb_n_buckets > 0);
142 ASSERT (lb1->lb_n_buckets > 0);
143 ASSERT (is_pow2 (lb0->lb_n_buckets));
144 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Dave Barachd7cb1b52016-12-09 09:52:16 -0500146 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147
Dave Barachd7cb1b52016-12-09 09:52:16 -0500148 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
149 {
150 flow_hash_config0 = lb0->lb_hash_config;
151 vnet_buffer (p0)->ip.flow_hash =
152 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700153 dpo0 =
154 load_balance_get_fwd_bucket (lb0,
155 (vnet_buffer (p0)->ip.flow_hash &
156 (lb0->lb_n_buckets_minus_1)));
157 }
158 else
159 {
160 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500161 }
162 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
163 {
164 flow_hash_config1 = lb1->lb_hash_config;
165 vnet_buffer (p1)->ip.flow_hash =
166 ip6_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700167 dpo1 =
168 load_balance_get_fwd_bucket (lb1,
169 (vnet_buffer (p1)->ip.flow_hash &
170 (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700172 else
173 {
174 dpo1 = load_balance_get_bucket_i (lb1, 0);
175 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100176 next0 = dpo0->dpoi_next_node;
177 next1 = dpo1->dpoi_next_node;
178
179 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500180 if (PREDICT_FALSE
181 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100182 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500183 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100184 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
185 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500186 if (PREDICT_FALSE
187 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100188 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500189 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100190 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
191 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100192 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
193 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194
Dave Barach75fc8542016-10-11 16:16:02 -0400195 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200196 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400197 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200198 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199
200 from += 2;
201 to_next += 2;
202 n_left_to_next -= 2;
203 n_left_from -= 2;
204
Dave Barachd7cb1b52016-12-09 09:52:16 -0500205 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500207 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 switch (wrong_next)
209 {
210 case 1:
211 /* A B A */
212 to_next[-2] = pi1;
213 to_next -= 1;
214 n_left_to_next += 1;
215 vlib_set_next_frame_buffer (vm, node, next0, pi0);
216 break;
217
218 case 2:
219 /* A A B */
220 to_next -= 1;
221 n_left_to_next += 1;
222 vlib_set_next_frame_buffer (vm, node, next1, pi1);
223 break;
224
225 case 3:
226 /* A B C */
227 to_next -= 2;
228 n_left_to_next += 2;
229 vlib_set_next_frame_buffer (vm, node, next0, pi0);
230 vlib_set_next_frame_buffer (vm, node, next1, pi1);
231 if (next0 == next1)
232 {
233 /* A B B */
234 vlib_put_next_frame (vm, node, next, n_left_to_next);
235 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500236 vlib_get_next_frame (vm, node, next, to_next,
237 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 }
239 }
240 }
241 }
Dave Barach75fc8542016-10-11 16:16:02 -0400242
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 while (n_left_from > 0 && n_left_to_next > 0)
244 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500245 vlib_buffer_t *p0;
246 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100247 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500249 load_balance_t *lb0;
250 ip6_address_t *dst_addr0;
251 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100252 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253
254 pi0 = from[0];
255 to_next[0] = pi0;
256
257 p0 = vlib_get_buffer (vm, pi0);
258
259 ip0 = vlib_buffer_get_current (p0);
260
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100261 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200262
Dave Barachd7cb1b52016-12-09 09:52:16 -0500263 fib_index0 =
264 vec_elt (im->fib_index_by_sw_if_index,
265 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
266 fib_index0 =
267 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
268 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269
Dave Barachd7cb1b52016-12-09 09:52:16 -0500270 flow_hash_config0 = ip6_fib_get (fib_index0)->flow_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100272 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100274 lb0 = load_balance_get (lbi0);
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
351 a->neighbor_probe_adj_index = ~0;
352 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500353 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100354 fib_node_index_t fei;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355
Neale Rannsf12a83f2017-04-18 09:09:40 -0700356 fei = fib_table_entry_update_one_path (fib_index,
357 &pfx,
358 FIB_SOURCE_INTERFACE,
359 (FIB_ENTRY_FLAG_CONNECTED |
360 FIB_ENTRY_FLAG_ATTACHED),
361 FIB_PROTOCOL_IP6,
362 /* No next-hop address */
363 NULL, sw_if_index,
364 /* invalid FIB index */
365 ~0, 1,
366 /* no label stack */
367 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500368 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
369 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100371 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500373 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100374 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500375 lm->classify_table_index_by_sw_if_index[sw_if_index];
376 if (classify_table_index != (u32) ~ 0)
377 {
378 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100379
Dave Barachd7cb1b52016-12-09 09:52:16 -0500380 dpo_set (&dpo,
381 DPO_CLASSIFY,
382 DPO_PROTO_IP6,
383 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100384
Dave Barachd7cb1b52016-12-09 09:52:16 -0500385 fib_table_entry_special_dpo_add (fib_index,
386 &pfx,
387 FIB_SOURCE_CLASSIFY,
388 FIB_ENTRY_FLAG_NONE, &dpo);
389 dpo_reset (&dpo);
390 }
391 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100392
Neale Rannsf12a83f2017-04-18 09:09:40 -0700393 fib_table_entry_update_one_path (fib_index, &pfx,
394 FIB_SOURCE_INTERFACE,
395 (FIB_ENTRY_FLAG_CONNECTED |
396 FIB_ENTRY_FLAG_LOCAL),
397 FIB_PROTOCOL_IP6,
398 &pfx.fp_addr,
399 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500400 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401}
402
403static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100404ip6_del_interface_routes (ip6_main_t * im,
405 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500406 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500408 fib_prefix_t pfx = {
409 .fp_len = address_length,
410 .fp_proto = FIB_PROTOCOL_IP6,
411 .fp_addr.ip6 = *address,
412 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413
Dave Barachd7cb1b52016-12-09 09:52:16 -0500414 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418 }
419
Dave Barachd7cb1b52016-12-09 09:52:16 -0500420 pfx.fp_len = 128;
421 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422}
423
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100424void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500425ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100426{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500427 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100431 /*
432 * enable/disable only on the 1<->0 transition
433 */
434 if (is_enable)
435 {
436 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500437 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100438 }
439 else
440 {
Neale Ranns75152282017-01-09 01:00:45 -0800441 /* The ref count is 0 when an address is removed from an interface that has
442 * no address - this is not a ciritical error */
443 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
444 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500445 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446 }
447
Damjan Marion8b3191e2016-11-09 19:54:20 +0100448 vnet_feature_enable_disable ("ip6-unicast", "ip6-lookup", sw_if_index,
449 is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450
Neale Ranns32e1c012016-11-22 17:07:28 +0000451 vnet_feature_enable_disable ("ip6-multicast", "ip6-mfib-forward-lookup",
452 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100453
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454}
455
Neale Rannsdf089a82016-10-02 16:39:06 +0100456/* get first interface address */
457ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800458ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100459{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 ip_lookup_main_t *lm = &im->lookup_main;
461 ip_interface_address_t *ia = 0;
462 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100463
Dave Barachd7cb1b52016-12-09 09:52:16 -0500464 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100465 foreach_ip_interface_address (lm, ia, sw_if_index,
466 1 /* honor unnumbered */,
467 ({
468 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
469 result = a;
470 break;
471 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100473 return result;
474}
475
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100476clib_error_t *
477ip6_add_del_interface_address (vlib_main_t * vm,
478 u32 sw_if_index,
479 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500480 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 vnet_main_t *vnm = vnet_get_main ();
483 ip6_main_t *im = &ip6_main;
484 ip_lookup_main_t *lm = &im->lookup_main;
485 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500487 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488
489 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000490 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
491
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492 ip6_addr_fib_init (&ip6_af, address,
493 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
494 vec_add1 (addr_fib, ip6_af);
495
496 {
497 uword elts_before = pool_elts (lm->if_address_pool);
498
499 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500500 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501 if (error)
502 goto done;
503
504 /* Pool did not grow: add duplicate address. */
505 if (elts_before == pool_elts (lm->if_address_pool))
506 goto done;
507 }
508
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000510
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100511 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100513 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500514 ip6_add_interface_routes (vnm, sw_if_index,
515 im, ip6_af.fib_index,
516 pool_elt_at_index (lm->if_address_pool,
517 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
519 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 vec_foreach (cb, im->add_del_interface_address_callbacks)
522 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 }
525
Dave Barachd7cb1b52016-12-09 09:52:16 -0500526done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 vec_free (addr_fib);
528 return error;
529}
530
531clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500532ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500534 ip6_main_t *im = &ip6_main;
535 ip_interface_address_t *ia;
536 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 u32 is_admin_up, fib_index;
538
539 /* Fill in lookup tables with default table (0). */
540 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
541
Dave Barachd7cb1b52016-12-09 09:52:16 -0500542 vec_validate_init_empty (im->
543 lookup_main.if_address_pool_index_by_sw_if_index,
544 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545
546 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
547
548 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
549
Dave Barachd7cb1b52016-12-09 09:52:16 -0500550 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400551 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552 0 /* honor unnumbered */,
553 ({
554 a = ip_interface_address_get_address (&im->lookup_main, ia);
555 if (is_admin_up)
556 ip6_add_interface_routes (vnm, sw_if_index,
557 im, fib_index,
558 ia);
559 else
560 ip6_del_interface_routes (im, fib_index,
561 a, ia->address_length);
562 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500563 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
565 return 0;
566}
567
568VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
569
Dave Barachd6534602016-06-14 18:38:02 -0400570/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500571/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100572VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
573{
574 .arc_name = "ip6-unicast",
575 .start_nodes = VNET_FEATURES ("ip6-input"),
576 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
577};
578
Dave Barachd7cb1b52016-12-09 09:52:16 -0500579VNET_FEATURE_INIT (ip6_flow_classify, static) =
580{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100581 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700582 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100583 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700584};
585
Dave Barachd7cb1b52016-12-09 09:52:16 -0500586VNET_FEATURE_INIT (ip6_inacl, static) =
587{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100588 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400589 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100590 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400591};
592
Dave Barachd7cb1b52016-12-09 09:52:16 -0500593VNET_FEATURE_INIT (ip6_policer_classify, static) =
594{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100595 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700596 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100597 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700598};
599
Dave Barachd7cb1b52016-12-09 09:52:16 -0500600VNET_FEATURE_INIT (ip6_ipsec, static) =
601{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100602 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400603 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100604 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400605};
606
Dave Barachd7cb1b52016-12-09 09:52:16 -0500607VNET_FEATURE_INIT (ip6_l2tp, static) =
608{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100609 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400610 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100611 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400612};
613
Dave Barachd7cb1b52016-12-09 09:52:16 -0500614VNET_FEATURE_INIT (ip6_vpath, static) =
615{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100616 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400617 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500618 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
619};
620
621VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
622{
623 .arc_name = "ip6-unicast",
624 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100625 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400626};
627
Dave Barachd7cb1b52016-12-09 09:52:16 -0500628VNET_FEATURE_INIT (ip6_lookup, static) =
629{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100630 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400631 .node_name = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100632 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400633};
634
Dave Barachd7cb1b52016-12-09 09:52:16 -0500635VNET_FEATURE_INIT (ip6_drop, static) =
636{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100637 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638 .node_name = "ip6-drop",
639 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100640};
641
Dave Barachd6534602016-06-14 18:38:02 -0400642/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100643VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
644{
645 .arc_name = "ip6-multicast",
646 .start_nodes = VNET_FEATURES ("ip6-input"),
647 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
648};
649
650VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
651 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400652 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000653 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400654};
655
Damjan Marion8b3191e2016-11-09 19:54:20 +0100656VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
657 .arc_name = "ip6-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +0000658 .node_name = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100659 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400660};
661
Damjan Marion8b3191e2016-11-09 19:54:20 +0100662VNET_FEATURE_INIT (ip6_drop_mc, static) = {
663 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100664 .node_name = "ip6-drop",
665 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100666};
Dave Barach5331c722016-08-17 11:54:30 -0400667
668/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100669VNET_FEATURE_ARC_INIT (ip6_output, static) =
670{
671 .arc_name = "ip6-output",
672 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
673 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400674};
675
Matus Fabian08a6f012016-11-15 06:08:51 -0800676VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
677 .arc_name = "ip6-output",
678 .node_name = "ipsec-output-ip6",
679 .runs_before = VNET_FEATURES ("interface-output"),
680};
681
Damjan Marion8b3191e2016-11-09 19:54:20 +0100682VNET_FEATURE_INIT (ip6_interface_output, static) = {
683 .arc_name = "ip6-output",
684 .node_name = "interface-output",
685 .runs_before = 0, /* not before any other features */
686};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400688
Ed Warnickecb9cada2015-12-08 15:45:58 -0700689clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500690ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100692 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
693 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694
Damjan Marion8b3191e2016-11-09 19:54:20 +0100695 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
696 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697
Damjan Marion8b3191e2016-11-09 19:54:20 +0100698 vnet_feature_enable_disable ("ip6-output", "interface-output", sw_if_index,
699 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700
Ed Warnickecb9cada2015-12-08 15:45:58 -0700701 return /* no error */ 0;
702}
703
704VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
705
Damjan Marionaca64c92016-04-13 09:48:56 +0200706static uword
707ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500708 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200709{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100710 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200711}
712
Dave Barachd7cb1b52016-12-09 09:52:16 -0500713static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100714
Dave Barachd7cb1b52016-12-09 09:52:16 -0500715/* *INDENT-OFF* */
716VLIB_REGISTER_NODE (ip6_lookup_node) =
717{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718 .function = ip6_lookup,
719 .name = "ip6-lookup",
720 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100721 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200722 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200723 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500725/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726
Dave Barachd7cb1b52016-12-09 09:52:16 -0500727VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200728
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100729always_inline uword
730ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500731 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200732{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500733 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
734 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100735 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200736 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100738
739 from = vlib_frame_vector_args (frame);
740 n_left_from = frame->n_vectors;
741 next = node->cached_next_index;
742
743 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100745
746 while (n_left_from > 0)
747 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500748 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100749
Dave Barach75fc8542016-10-11 16:16:02 -0400750
Neale Ranns2be95c12016-11-19 13:50:04 +0000751 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500752 {
753 ip_lookup_next_t next0, next1;
754 const load_balance_t *lb0, *lb1;
755 vlib_buffer_t *p0, *p1;
756 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
757 const ip6_header_t *ip0, *ip1;
758 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000759
Dave Barachd7cb1b52016-12-09 09:52:16 -0500760 /* Prefetch next iteration. */
761 {
762 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000763
Dave Barachd7cb1b52016-12-09 09:52:16 -0500764 p2 = vlib_get_buffer (vm, from[2]);
765 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000766
Dave Barachd7cb1b52016-12-09 09:52:16 -0500767 vlib_prefetch_buffer_header (p2, STORE);
768 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000769
Dave Barachd7cb1b52016-12-09 09:52:16 -0500770 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
771 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
772 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000773
Dave Barachd7cb1b52016-12-09 09:52:16 -0500774 pi0 = to_next[0] = from[0];
775 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000776
Dave Barachd7cb1b52016-12-09 09:52:16 -0500777 from += 2;
778 n_left_from -= 2;
779 to_next += 2;
780 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000781
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 p0 = vlib_get_buffer (vm, pi0);
783 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000784
Dave Barachd7cb1b52016-12-09 09:52:16 -0500785 ip0 = vlib_buffer_get_current (p0);
786 ip1 = vlib_buffer_get_current (p1);
787 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
788 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000789
Dave Barachd7cb1b52016-12-09 09:52:16 -0500790 lb0 = load_balance_get (lbi0);
791 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000792
Dave Barachd7cb1b52016-12-09 09:52:16 -0500793 /*
794 * this node is for via FIBs we can re-use the hash value from the
795 * to node if present.
796 * We don't want to use the same hash value at each level in the recursion
797 * graph as that would lead to polarisation
798 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000799 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000800
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
802 {
803 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
804 {
805 hc0 = vnet_buffer (p0)->ip.flow_hash =
806 vnet_buffer (p0)->ip.flow_hash >> 1;
807 }
808 else
809 {
810 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000811 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700813 dpo0 =
814 load_balance_get_fwd_bucket (lb0,
815 (hc0 &
816 lb0->lb_n_buckets_minus_1));
817 }
818 else
819 {
820 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500821 }
822 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
823 {
824 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
825 {
826 hc1 = vnet_buffer (p1)->ip.flow_hash =
827 vnet_buffer (p1)->ip.flow_hash >> 1;
828 }
829 else
830 {
831 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000832 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500833 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700834 dpo1 =
835 load_balance_get_fwd_bucket (lb1,
836 (hc1 &
837 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500838 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700839 else
840 {
841 dpo1 = load_balance_get_bucket_i (lb1, 0);
842 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000843
Dave Barachd7cb1b52016-12-09 09:52:16 -0500844 next0 = dpo0->dpoi_next_node;
845 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000846
Dave Barachd7cb1b52016-12-09 09:52:16 -0500847 /* Only process the HBH Option Header if explicitly configured to do so */
848 if (PREDICT_FALSE
849 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
850 {
851 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
852 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
853 }
854 /* Only process the HBH Option Header if explicitly configured to do so */
855 if (PREDICT_FALSE
856 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
857 {
858 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
859 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
860 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000861
Dave Barachd7cb1b52016-12-09 09:52:16 -0500862 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
863 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000864
Dave Barachd7cb1b52016-12-09 09:52:16 -0500865 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200866 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500867 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200868 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000869
Dave Barachd7cb1b52016-12-09 09:52:16 -0500870 vlib_validate_buffer_enqueue_x2 (vm, node, next,
871 to_next, n_left_to_next,
872 pi0, pi1, next0, next1);
873 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000874
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100875 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500876 {
877 ip_lookup_next_t next0;
878 const load_balance_t *lb0;
879 vlib_buffer_t *p0;
880 u32 pi0, lbi0, hc0;
881 const ip6_header_t *ip0;
882 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100883
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884 pi0 = from[0];
885 to_next[0] = pi0;
886 from += 1;
887 to_next += 1;
888 n_left_to_next -= 1;
889 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100890
Dave Barachd7cb1b52016-12-09 09:52:16 -0500891 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100892
Dave Barachd7cb1b52016-12-09 09:52:16 -0500893 ip0 = vlib_buffer_get_current (p0);
894 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100895
Dave Barachd7cb1b52016-12-09 09:52:16 -0500896 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100897
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000898 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500899 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
900 {
901 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
902 {
903 hc0 = vnet_buffer (p0)->ip.flow_hash =
904 vnet_buffer (p0)->ip.flow_hash >> 1;
905 }
906 else
907 {
908 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000909 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500910 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700911 dpo0 =
912 load_balance_get_fwd_bucket (lb0,
913 (hc0 &
914 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700916 else
917 {
918 dpo0 = load_balance_get_bucket_i (lb0, 0);
919 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100920
Dave Barachd7cb1b52016-12-09 09:52:16 -0500921 next0 = dpo0->dpoi_next_node;
922 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000923
Dave Barachd7cb1b52016-12-09 09:52:16 -0500924 /* Only process the HBH Option Header if explicitly configured to do so */
925 if (PREDICT_FALSE
926 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
927 {
928 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
929 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
930 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000931
Dave Barachd7cb1b52016-12-09 09:52:16 -0500932 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200933 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100934
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935 vlib_validate_buffer_enqueue_x1 (vm, node, next,
936 to_next, n_left_to_next,
937 pi0, next0);
938 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100939
940 vlib_put_next_frame (vm, node, next, n_left_to_next);
941 }
942
943 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200944}
945
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946/* *INDENT-OFF* */
947VLIB_REGISTER_NODE (ip6_load_balance_node) =
948{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100949 .function = ip6_load_balance,
950 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200951 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200952 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100953 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200954};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500955/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200956
Dave Barachd7cb1b52016-12-09 09:52:16 -0500957VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200958
Dave Barachd7cb1b52016-12-09 09:52:16 -0500959typedef struct
960{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961 /* Adjacency taken. */
962 u32 adj_index;
963 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500964 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700965
966 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500967 u8 packet_data[128 - 1 * sizeof (u32)];
968}
969ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970
John Lo2b81eb82017-01-30 13:12:10 -0500971u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500972format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100974 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
975 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100977 uword indent = format_get_indent (s);
978
Dave Barachd7cb1b52016-12-09 09:52:16 -0500979 s = format (s, "%U%U",
980 format_white_space, indent,
981 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100982 return s;
983}
984
Dave Barachd7cb1b52016-12-09 09:52:16 -0500985static u8 *
986format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100987{
988 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
989 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500990 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991 uword indent = format_get_indent (s);
992
John Loac8146c2016-09-27 17:44:02 -0400993 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500994 t->fib_index, t->adj_index, t->flow_hash);
995 s = format (s, "\n%U%U",
996 format_white_space, indent,
997 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100998 return s;
999}
Pierre Pfister0febaf12016-06-08 12:23:21 +01001000
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001
Dave Barachd7cb1b52016-12-09 09:52:16 -05001002static u8 *
1003format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001004{
1005 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1006 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001007 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001008 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001009
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001010 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001011 t->fib_index, t->adj_index, format_ip_adjacency,
1012 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001013 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001014 format_white_space, indent,
1015 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001016 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017 return s;
1018}
1019
1020/* Common trace function for all ip6-forward next nodes. */
1021void
1022ip6_forward_next_trace (vlib_main_t * vm,
1023 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001024 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001025{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 u32 *from, n_left;
1027 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028
1029 n_left = frame->n_vectors;
1030 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001031
Ed Warnickecb9cada2015-12-08 15:45:58 -07001032 while (n_left >= 4)
1033 {
1034 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 vlib_buffer_t *b0, *b1;
1036 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037
1038 /* Prefetch next iteration. */
1039 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1040 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1041
1042 bi0 = from[0];
1043 bi1 = from[1];
1044
1045 b0 = vlib_get_buffer (vm, bi0);
1046 b1 = vlib_get_buffer (vm, bi1);
1047
1048 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1049 {
1050 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1051 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1053 t0->fib_index =
1054 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1055 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1056 vec_elt (im->fib_index_by_sw_if_index,
1057 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001058
Damjan Marionf1213b82016-03-13 02:22:06 +01001059 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001060 vlib_buffer_get_current (b0),
1061 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
1063 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1064 {
1065 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1066 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001067 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1068 t1->fib_index =
1069 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1070 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1071 vec_elt (im->fib_index_by_sw_if_index,
1072 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001073
Damjan Marionf1213b82016-03-13 02:22:06 +01001074 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001075 vlib_buffer_get_current (b1),
1076 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 }
1078 from += 2;
1079 n_left -= 2;
1080 }
1081
1082 while (n_left >= 1)
1083 {
1084 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085 vlib_buffer_t *b0;
1086 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001087
1088 bi0 = from[0];
1089
1090 b0 = vlib_get_buffer (vm, bi0);
1091
1092 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1093 {
1094 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1095 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001096 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1097 t0->fib_index =
1098 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1099 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1100 vec_elt (im->fib_index_by_sw_if_index,
1101 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001102
Damjan Marionf1213b82016-03-13 02:22:06 +01001103 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 vlib_buffer_get_current (b0),
1105 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106 }
1107 from += 1;
1108 n_left -= 1;
1109 }
1110}
1111
1112static uword
1113ip6_drop_or_punt (vlib_main_t * vm,
1114 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001115 vlib_frame_t * frame, ip6_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001117 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118 uword n_packets = frame->n_vectors;
1119
Dave Barachd7cb1b52016-12-09 09:52:16 -05001120 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121 /* stride */ 1,
1122 n_packets,
1123 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001124 ip6_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125
1126 if (node->flags & VLIB_NODE_FLAG_TRACE)
1127 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1128
1129 return n_packets;
1130}
1131
1132static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1134{
1135 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1136}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137
1138static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1140{
1141 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1142}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143
Dave Barachd7cb1b52016-12-09 09:52:16 -05001144/* *INDENT-OFF* */
1145VLIB_REGISTER_NODE (ip6_drop_node, static) =
1146{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147 .function = ip6_drop,
1148 .name = "ip6-drop",
1149 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001152 .next_nodes =
1153 {
1154 [0] = "error-drop",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001156/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157
Dave Barachd7cb1b52016-12-09 09:52:16 -05001158VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001159
Dave Barachd7cb1b52016-12-09 09:52:16 -05001160/* *INDENT-OFF* */
1161VLIB_REGISTER_NODE (ip6_punt_node, static) =
1162{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163 .function = ip6_punt,
1164 .name = "ip6-punt",
1165 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001168 .next_nodes =
1169 {
1170 [0] = "error-punt",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001171};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001172/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
Dave Barachd7cb1b52016-12-09 09:52:16 -05001174VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001175
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177u16
1178ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1179 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180{
1181 ip_csum_t sum0;
1182 u16 sum16, payload_length_host_byte_order;
1183 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001184 u32 headers_size = sizeof (ip0[0]);
1185 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186
Dave Barachd7cb1b52016-12-09 09:52:16 -05001187 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188 *bogus_lengthp = 0;
1189
1190 /* Initialize checksum with ip header. */
1191 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1192 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1193 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001194
Ed Warnickecb9cada2015-12-08 15:45:58 -07001195 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1196 {
1197 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198 clib_mem_unaligned (&ip0->
1199 src_address.as_uword[i],
1200 uword));
1201 sum0 =
1202 ip_csum_with_carry (sum0,
1203 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1204 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205 }
1206
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301207 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1208 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001209 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 u32 skip_bytes;
1212 ip6_hop_by_hop_ext_t *ext_hdr =
1213 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214
1215 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301216 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1217 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001218
Dave Barachd7cb1b52016-12-09 09:52:16 -05001219 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1220 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001221
Dave Barachd7cb1b52016-12-09 09:52:16 -05001222 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001224 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225
1226 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 if (p0 && n_this_buffer + headers_size > p0->current_length)
1228 n_this_buffer =
1229 p0->current_length >
1230 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231 while (1)
1232 {
1233 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1234 n_bytes_left -= n_this_buffer;
1235 if (n_bytes_left == 0)
1236 break;
1237
1238 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001239 {
1240 *bogus_lengthp = 1;
1241 return 0xfefe;
1242 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243 p0 = vlib_get_buffer (vm, p0->next_buffer);
1244 data_this_buffer = vlib_buffer_get_current (p0);
1245 n_this_buffer = p0->current_length;
1246 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247
Dave Barachd7cb1b52016-12-09 09:52:16 -05001248 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249
1250 return sum16;
1251}
1252
Dave Barachd7cb1b52016-12-09 09:52:16 -05001253u32
1254ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001255{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001256 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1257 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258 u16 sum16;
1259 int bogus_length;
1260
1261 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1262 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1263 || ip0->protocol == IP_PROTOCOL_ICMP6
1264 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001265 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266
1267 udp0 = (void *) (ip0 + 1);
1268 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1269 {
1270 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1271 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1272 return p0->flags;
1273 }
1274
1275 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1276
1277 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1278 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1279
1280 return p0->flags;
1281}
1282
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301283/**
1284 * @brief returns number of links on which src is reachable.
1285 */
1286always_inline int
1287ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1288{
1289 const load_balance_t *lb0;
1290 index_t lbi;
1291
1292 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1293 vnet_buffer
1294 (b)->sw_if_index[VLIB_RX],
1295 &i->src_address);
1296
1297 lb0 = load_balance_get (lbi);
1298
1299 return (fib_urpf_check_size (lb0->lb_urpf));
1300}
1301
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001303ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001304{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001305 ip6_main_t *im = &ip6_main;
1306 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001308 u32 *from, *to_next, n_left_from, n_left_to_next;
1309 vlib_node_runtime_t *error_node =
1310 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001311
1312 from = vlib_frame_vector_args (frame);
1313 n_left_from = frame->n_vectors;
1314 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001315
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316 if (node->flags & VLIB_NODE_FLAG_TRACE)
1317 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1318
1319 while (n_left_from > 0)
1320 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001321 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001322
1323 while (n_left_from >= 4 && n_left_to_next >= 2)
1324 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001325 vlib_buffer_t *p0, *p1;
1326 ip6_header_t *ip0, *ip1;
1327 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328 u32 pi0, ip_len0, udp_len0, flags0, next0;
1329 u32 pi1, ip_len1, udp_len1, flags1, next1;
1330 i32 len_diff0, len_diff1;
1331 u8 error0, type0, good_l4_checksum0;
1332 u8 error1, type1, good_l4_checksum1;
Shwethab78292e2016-09-13 11:51:00 +01001333 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001334
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335 pi0 = to_next[0] = from[0];
1336 pi1 = to_next[1] = from[1];
1337 from += 2;
1338 n_left_from -= 2;
1339 to_next += 2;
1340 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001341
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342 p0 = vlib_get_buffer (vm, pi0);
1343 p1 = vlib_get_buffer (vm, pi1);
1344
1345 ip0 = vlib_buffer_get_current (p0);
1346 ip1 = vlib_buffer_get_current (p1);
1347
Filip Tehlarb601f222017-01-02 10:22:56 +01001348 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1349 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1350
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1352 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1353
1354 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1355 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1356
1357 flags0 = p0->flags;
1358 flags1 = p1->flags;
1359
1360 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1361 good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001362 len_diff0 = 0;
1363 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364
Dave Barachd7cb1b52016-12-09 09:52:16 -05001365 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1366 IP_PROTOCOL_UDP,
1367 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001368 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001369 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001370 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001371 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1372 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001373 /* Verify UDP length. */
1374 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1375 udp_len0 = clib_net_to_host_u16 (udp0->length);
1376 len_diff0 = ip_len0 - udp_len0;
1377 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001378 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1379 IP_PROTOCOL_UDP,
1380 &udp_offset1)))
Shwethab78292e2016-09-13 11:51:00 +01001381 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001382 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001383 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001384 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1385 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001386 /* Verify UDP length. */
1387 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1388 udp_len1 = clib_net_to_host_u16 (udp1->length);
1389 len_diff1 = ip_len1 - udp_len1;
1390 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391
1392 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1393 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1394
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1396 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1397
1398 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001399 && !good_l4_checksum0
1400 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401 {
1402 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1403 good_l4_checksum0 =
1404 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1405 }
1406 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001407 && !good_l4_checksum1
1408 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409 {
1410 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1411 good_l4_checksum1 =
1412 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1413 }
1414
1415 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1416
1417 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1418 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1419
Dave Barachd7cb1b52016-12-09 09:52:16 -05001420 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1421 IP6_ERROR_UDP_CHECKSUM);
1422 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1423 IP6_ERROR_ICMP_CHECKSUM);
1424 error0 =
1425 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1426 error1 =
1427 (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001428
1429 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001430 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001431 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1432 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001433 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001434 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301435 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001436 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001438 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1439 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001440 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001441 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301442 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001443 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444 }
1445
Dave Barachd7cb1b52016-12-09 09:52:16 -05001446 next0 =
1447 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1448 next1 =
1449 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450
1451 p0->error = error_node->errors[error0];
1452 p1->error = error_node->errors[error1];
1453
1454 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1455 to_next, n_left_to_next,
1456 pi0, pi1, next0, next1);
1457 }
1458
1459 while (n_left_from > 0 && n_left_to_next > 0)
1460 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001461 vlib_buffer_t *p0;
1462 ip6_header_t *ip0;
1463 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001464 u32 pi0, ip_len0, udp_len0, flags0, next0;
1465 i32 len_diff0;
1466 u8 error0, type0, good_l4_checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001467 u32 udp_offset0;
Dave Barach75fc8542016-10-11 16:16:02 -04001468
Ed Warnickecb9cada2015-12-08 15:45:58 -07001469 pi0 = to_next[0] = from[0];
1470 from += 1;
1471 n_left_from -= 1;
1472 to_next += 1;
1473 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001474
Ed Warnickecb9cada2015-12-08 15:45:58 -07001475 p0 = vlib_get_buffer (vm, pi0);
1476
1477 ip0 = vlib_buffer_get_current (p0);
1478
Filip Tehlarb601f222017-01-02 10:22:56 +01001479 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1480
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1482 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1483
1484 flags0 = p0->flags;
1485
1486 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001487 len_diff0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488
Dave Barachd7cb1b52016-12-09 09:52:16 -05001489 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1490 IP_PROTOCOL_UDP,
1491 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001492 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001493 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001494 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001495 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1496 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001497 /* Verify UDP length. */
1498 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1499 udp_len0 = clib_net_to_host_u16 (udp0->length);
1500 len_diff0 = ip_len0 - udp_len0;
1501 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001502
1503 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001504 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1505
1506 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001507 && !good_l4_checksum0
1508 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001509 {
1510 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1511 good_l4_checksum0 =
1512 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1513 }
1514
1515 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1516
1517 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1518
Dave Barachd7cb1b52016-12-09 09:52:16 -05001519 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1520 IP6_ERROR_UDP_CHECKSUM);
1521 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1522 IP6_ERROR_ICMP_CHECKSUM);
1523 error0 =
1524 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001525
Dave Barachd7cb1b52016-12-09 09:52:16 -05001526 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001527 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1528 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001530 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301531 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001532 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533 }
1534
Dave Barachd7cb1b52016-12-09 09:52:16 -05001535 next0 =
1536 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537
1538 p0->error = error_node->errors[error0];
1539
1540 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1541 to_next, n_left_to_next,
1542 pi0, next0);
1543 }
Dave Barach75fc8542016-10-11 16:16:02 -04001544
Ed Warnickecb9cada2015-12-08 15:45:58 -07001545 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1546 }
1547
1548 return frame->n_vectors;
1549}
1550
Dave Barachd7cb1b52016-12-09 09:52:16 -05001551/* *INDENT-OFF* */
1552VLIB_REGISTER_NODE (ip6_local_node, static) =
1553{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001554 .function = ip6_local,
1555 .name = "ip6-local",
1556 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001558 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001559 .next_nodes =
1560 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561 [IP_LOCAL_NEXT_DROP] = "error-drop",
1562 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1564 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1565 },
1566};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001567/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001568
Dave Barachd7cb1b52016-12-09 09:52:16 -05001569VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001570
Dave Barachd7cb1b52016-12-09 09:52:16 -05001571void
1572ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001573{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001574 vlib_main_t *vm = vlib_get_main ();
1575 ip6_main_t *im = &ip6_main;
1576 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001577
1578 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001579 lm->local_next_by_ip_protocol[protocol] =
1580 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001581}
1582
Dave Barachd7cb1b52016-12-09 09:52:16 -05001583typedef enum
1584{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001586 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001587 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1588} ip6_discover_neighbor_next_t;
1589
Dave Barachd7cb1b52016-12-09 09:52:16 -05001590typedef enum
1591{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001592 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1593 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001594 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001595} ip6_discover_neighbor_error_t;
1596
1597static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001598ip6_discover_neighbor_inline (vlib_main_t * vm,
1599 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001600 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001602 vnet_main_t *vnm = vnet_get_main ();
1603 ip6_main_t *im = &ip6_main;
1604 ip_lookup_main_t *lm = &im->lookup_main;
1605 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606 uword n_left_from, n_left_to_next_drop;
1607 static f64 time_last_seed_change = -1e100;
1608 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001609 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001610 f64 time_now;
1611 int bogus_length;
1612
1613 if (node->flags & VLIB_NODE_FLAG_TRACE)
1614 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1615
1616 time_now = vlib_time_now (vm);
1617 if (time_now - time_last_seed_change > 1e-3)
1618 {
1619 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001620 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1621 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001622 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1623 hash_seeds[i] = r[i];
1624
1625 /* Mark all hash keys as been not-seen before. */
1626 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1627 hash_bitmap[i] = 0;
1628
1629 time_last_seed_change = time_now;
1630 }
1631
1632 from = vlib_frame_vector_args (frame);
1633 n_left_from = frame->n_vectors;
1634
1635 while (n_left_from > 0)
1636 {
1637 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1638 to_next_drop, n_left_to_next_drop);
1639
1640 while (n_left_from > 0 && n_left_to_next_drop > 0)
1641 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 vlib_buffer_t *p0;
1643 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001644 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1645 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001646 ip_adjacency_t *adj0;
1647 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648 u32 next0;
1649
1650 pi0 = from[0];
1651
1652 p0 = vlib_get_buffer (vm, pi0);
1653
1654 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1655
1656 ip0 = vlib_buffer_get_current (p0);
1657
Neale Ranns107e7d42017-04-11 09:55:19 -07001658 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001660 if (!is_glean)
1661 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001662 ip0->dst_address.as_u64[0] =
1663 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1664 ip0->dst_address.as_u64[1] =
1665 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001666 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001667
Ed Warnickecb9cada2015-12-08 15:45:58 -07001668 a0 = hash_seeds[0];
1669 b0 = hash_seeds[1];
1670 c0 = hash_seeds[2];
1671
1672 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1673 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1674
1675 a0 ^= sw_if_index0;
1676 b0 ^= ip0->dst_address.as_u32[0];
1677 c0 ^= ip0->dst_address.as_u32[1];
1678
1679 hash_v3_mix32 (a0, b0, c0);
1680
1681 b0 ^= ip0->dst_address.as_u32[2];
1682 c0 ^= ip0->dst_address.as_u32[3];
1683
1684 hash_v3_finalize32 (a0, b0, c0);
1685
1686 c0 &= BITS (hash_bitmap) - 1;
1687 c0 = c0 / BITS (uword);
1688 m0 = (uword) 1 << (c0 % BITS (uword));
1689
1690 bm0 = hash_bitmap[c0];
1691 drop0 = (bm0 & m0) != 0;
1692
1693 /* Mark it as seen. */
1694 hash_bitmap[c0] = bm0 | m0;
1695
1696 from += 1;
1697 n_left_from -= 1;
1698 to_next_drop[0] = pi0;
1699 to_next_drop += 1;
1700 n_left_to_next_drop -= 1;
1701
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001703
Dave Barachd7cb1b52016-12-09 09:52:16 -05001704 /* If the interface is link-down, drop the pkt */
1705 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1706 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001707
Dave Barach75fc8542016-10-11 16:16:02 -04001708 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001709 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1710 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001711 if (drop0)
1712 continue;
1713
Neale Rannsb80c5362016-10-08 13:03:40 +01001714 /*
1715 * the adj has been updated to a rewrite but the node the DPO that got
1716 * us here hasn't - yet. no big deal. we'll drop while we wait.
1717 */
1718 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1719 continue;
1720
Ed Warnickecb9cada2015-12-08 15:45:58 -07001721 {
1722 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001723 icmp6_neighbor_solicitation_header_t *h0;
1724 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001725
Dave Barach75fc8542016-10-11 16:16:02 -04001726 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001727 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728
Dave Barach75fc8542016-10-11 16:16:02 -04001729 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001730 * Build ethernet header.
1731 * Choose source address based on destination lookup
1732 * adjacency.
1733 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001734 if (ip6_src_address_for_packet (lm,
1735 sw_if_index0,
1736 &h0->ip.src_address))
1737 {
1738 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001739 p0->error =
1740 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1741 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001742 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001743 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001744
Dave Barach75fc8542016-10-11 16:16:02 -04001745 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001746 * Destination address is a solicited node multicast address.
1747 * We need to fill in
1748 * the low 24 bits with low 24 bits of target's address.
1749 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001750 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1751 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1752 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1753
1754 h0->neighbor.target_address = ip0->dst_address;
1755
Dave Barach75fc8542016-10-11 16:16:02 -04001756 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001757 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001758
Dave Barachd7cb1b52016-12-09 09:52:16 -05001759 /* $$$$ appears we need this; why is the checksum non-zero? */
1760 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001761 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001762 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1763 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764
Dave Barachd7cb1b52016-12-09 09:52:16 -05001765 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766
1767 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1768 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001769 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771
1772 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001773 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1775
John Lod1f5d042016-04-12 18:20:39 -04001776 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777
1778 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1779 }
1780 }
1781
Dave Barach75fc8542016-10-11 16:16:02 -04001782 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001783 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001784 }
1785
1786 return frame->n_vectors;
1787}
1788
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001789static uword
1790ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001791 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001792{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001793 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001794}
1795
1796static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001797ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001798{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001800}
1801
Dave Barachd7cb1b52016-12-09 09:52:16 -05001802static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001804 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001805 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1806 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001807};
1808
Dave Barachd7cb1b52016-12-09 09:52:16 -05001809/* *INDENT-OFF* */
1810VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1811{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812 .function = ip6_discover_neighbor,
1813 .name = "ip6-discover-neighbor",
1814 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001815 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001816 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1817 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001818 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001819 .next_nodes =
1820 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001821 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001822 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001823 },
1824};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001825/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001826
Dave Barachd7cb1b52016-12-09 09:52:16 -05001827/* *INDENT-OFF* */
1828VLIB_REGISTER_NODE (ip6_glean_node) =
1829{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001830 .function = ip6_glean,
1831 .name = "ip6-glean",
1832 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001833 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001834 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1835 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001836 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837 .next_nodes =
1838 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001839 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1840 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1841 },
1842};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001843/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001844
Ed Warnickecb9cada2015-12-08 15:45:58 -07001845clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1847{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 vnet_main_t *vnm = vnet_get_main ();
1849 ip6_main_t *im = &ip6_main;
1850 icmp6_neighbor_solicitation_header_t *h;
1851 ip6_address_t *src;
1852 ip_interface_address_t *ia;
1853 ip_adjacency_t *adj;
1854 vnet_hw_interface_t *hi;
1855 vnet_sw_interface_t *si;
1856 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857 u32 bi = 0;
1858 int bogus_length;
1859
1860 si = vnet_get_sw_interface (vnm, sw_if_index);
1861
1862 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1863 {
1864 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001865 format_ip6_address, dst,
1866 format_vnet_sw_if_index_name, vnm,
1867 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 }
1869
Dave Barachd7cb1b52016-12-09 09:52:16 -05001870 src =
1871 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1872 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001873 {
1874 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001875 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001876 (0, "no matching interface address for destination %U (interface %U)",
1877 format_ip6_address, dst,
1878 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001879 }
1880
Dave Barachd7cb1b52016-12-09 09:52:16 -05001881 h =
1882 vlib_packet_template_get_packet (vm,
1883 &im->discover_neighbor_packet_template,
1884 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885
1886 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1887
1888 /* Destination address is a solicited node multicast address. We need to fill in
1889 the low 24 bits with low 24 bits of target's address. */
1890 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1891 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1892 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1893
1894 h->ip.src_address = src[0];
1895 h->neighbor.target_address = dst[0];
1896
Dave Barachd7cb1b52016-12-09 09:52:16 -05001897 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1898 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001899
Dave Barach75fc8542016-10-11 16:16:02 -04001900 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001902 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001903
1904 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001905 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1906 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907
1908 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns107e7d42017-04-11 09:55:19 -07001909 adj = adj_get (ia->neighbor_probe_adj_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1911 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1912
1913 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001914 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1915 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001916 to_next[0] = bi;
1917 f->n_vectors = 1;
1918 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1919 }
1920
1921 return /* no error */ 0;
1922}
1923
Dave Barachd7cb1b52016-12-09 09:52:16 -05001924typedef enum
1925{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001926 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001927 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928} ip6_rewrite_next_t;
1929
1930always_inline uword
1931ip6_rewrite_inline (vlib_main_t * vm,
1932 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001933 vlib_frame_t * frame,
1934 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001935{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001936 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1937 u32 *from = vlib_frame_vector_args (frame);
1938 u32 n_left_from, n_left_to_next, *to_next, next_index;
1939 vlib_node_runtime_t *error_node =
1940 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941
1942 n_left_from = frame->n_vectors;
1943 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02001944 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04001945
Ed Warnickecb9cada2015-12-08 15:45:58 -07001946 while (n_left_from > 0)
1947 {
1948 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1949
1950 while (n_left_from >= 4 && n_left_to_next >= 2)
1951 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001952 ip_adjacency_t *adj0, *adj1;
1953 vlib_buffer_t *p0, *p1;
1954 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001955 u32 pi0, rw_len0, next0, error0, adj_index0;
1956 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001957 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001958
Ed Warnickecb9cada2015-12-08 15:45:58 -07001959 /* Prefetch next iteration. */
1960 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001961 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001962
1963 p2 = vlib_get_buffer (vm, from[2]);
1964 p3 = vlib_get_buffer (vm, from[3]);
1965
1966 vlib_prefetch_buffer_header (p2, LOAD);
1967 vlib_prefetch_buffer_header (p3, LOAD);
1968
1969 CLIB_PREFETCH (p2->pre_data, 32, STORE);
1970 CLIB_PREFETCH (p3->pre_data, 32, STORE);
1971
1972 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1973 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1974 }
1975
1976 pi0 = to_next[0] = from[0];
1977 pi1 = to_next[1] = from[1];
1978
1979 from += 2;
1980 n_left_from -= 2;
1981 to_next += 2;
1982 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001983
Ed Warnickecb9cada2015-12-08 15:45:58 -07001984 p0 = vlib_get_buffer (vm, pi0);
1985 p1 = vlib_get_buffer (vm, pi1);
1986
Neale Rannsf06aea52016-11-29 06:51:37 -08001987 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1988 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001989
Ed Warnickecb9cada2015-12-08 15:45:58 -07001990 ip0 = vlib_buffer_get_current (p0);
1991 ip1 = vlib_buffer_get_current (p1);
1992
1993 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001994 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001995
Dave Barachd7cb1b52016-12-09 09:52:16 -05001996 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001997 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001998 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001999
2000 /* Input node should have reject packets with hop limit 0. */
2001 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002
2003 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004
2005 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006
Dave Barachd7cb1b52016-12-09 09:52:16 -05002007 /*
2008 * If the hop count drops below 1 when forwarding, generate
2009 * an ICMP response.
2010 */
2011 if (PREDICT_FALSE (hop_limit0 <= 0))
2012 {
2013 error0 = IP6_ERROR_TIME_EXPIRED;
2014 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2015 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2016 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2017 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2018 0);
2019 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002020 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002021 else
2022 {
2023 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2024 }
2025 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2026 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002027 i32 hop_limit1 = ip1->hop_limit;
2028
2029 /* Input node should have reject packets with hop limit 0. */
2030 ASSERT (ip1->hop_limit > 0);
2031
2032 hop_limit1 -= 1;
2033
2034 ip1->hop_limit = hop_limit1;
2035
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 /*
2037 * If the hop count drops below 1 when forwarding, generate
2038 * an ICMP response.
2039 */
2040 if (PREDICT_FALSE (hop_limit1 <= 0))
2041 {
2042 error1 = IP6_ERROR_TIME_EXPIRED;
2043 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2044 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2045 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2046 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2047 0);
2048 }
2049 }
2050 else
2051 {
2052 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2053 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002054 adj0 = adj_get (adj_index0);
2055 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002056
Ed Warnickecb9cada2015-12-08 15:45:58 -07002057 rw_len0 = adj0[0].rewrite_header.data_bytes;
2058 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002059 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2060 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002061
Neale Ranns9c6a6132017-02-21 05:33:14 -08002062 if (do_counters)
2063 {
2064 vlib_increment_combined_counter
2065 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002066 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002067 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2068 vlib_increment_combined_counter
2069 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002070 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002071 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2072 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002073
2074 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002075 error0 =
2076 (vlib_buffer_length_in_chain (vm, p0) >
2077 adj0[0].
2078 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2079 error0);
2080 error1 =
2081 (vlib_buffer_length_in_chain (vm, p1) >
2082 adj1[0].
2083 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2084 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002085
Dave Barachd7cb1b52016-12-09 09:52:16 -05002086 /* Don't adjust the buffer for hop count issue; icmp-error node
2087 * wants to see the IP headerr */
2088 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2089 {
2090 p0->current_data -= rw_len0;
2091 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002092
Dave Barachd7cb1b52016-12-09 09:52:16 -05002093 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2094 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2095 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002096
Neale Rannsb069a692017-03-15 12:34:25 -04002097 if (PREDICT_FALSE
2098 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2099 vnet_feature_arc_start (lm->output_feature_arc_index,
2100 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002101 }
2102 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2103 {
2104 p1->current_data -= rw_len1;
2105 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106
Dave Barachd7cb1b52016-12-09 09:52:16 -05002107 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2108 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2109 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002110
Neale Rannsb069a692017-03-15 12:34:25 -04002111 if (PREDICT_FALSE
2112 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2113 vnet_feature_arc_start (lm->output_feature_arc_index,
2114 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002115 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116
2117 /* Guess we are only writing on simple Ethernet header. */
2118 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002119 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002120
Neale Ranns5e575b12016-10-03 09:40:25 +01002121 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002122 {
2123 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2124 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2125 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002126 if (is_mcast)
2127 {
2128 /*
2129 * copy bytes from the IP address into the MAC rewrite
2130 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002131 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2132 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002133 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002134
Ed Warnickecb9cada2015-12-08 15:45:58 -07002135 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2136 to_next, n_left_to_next,
2137 pi0, pi1, next0, next1);
2138 }
2139
2140 while (n_left_from > 0 && n_left_to_next > 0)
2141 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002142 ip_adjacency_t *adj0;
2143 vlib_buffer_t *p0;
2144 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002145 u32 pi0, rw_len0;
2146 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002147 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002148
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149 pi0 = to_next[0] = from[0];
2150
2151 p0 = vlib_get_buffer (vm, pi0);
2152
Neale Rannsf06aea52016-11-29 06:51:37 -08002153 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002154
Neale Ranns107e7d42017-04-11 09:55:19 -07002155 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002156
Ed Warnickecb9cada2015-12-08 15:45:58 -07002157 ip0 = vlib_buffer_get_current (p0);
2158
2159 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002160 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161
2162 /* Check hop limit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002163 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002164 {
2165 i32 hop_limit0 = ip0->hop_limit;
2166
2167 ASSERT (ip0->hop_limit > 0);
2168
2169 hop_limit0 -= 1;
2170
2171 ip0->hop_limit = hop_limit0;
2172
Dave Barachd7cb1b52016-12-09 09:52:16 -05002173 if (PREDICT_FALSE (hop_limit0 <= 0))
2174 {
2175 /*
2176 * If the hop count drops below 1 when forwarding, generate
2177 * an ICMP response.
2178 */
2179 error0 = IP6_ERROR_TIME_EXPIRED;
2180 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2181 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2182 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2183 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2184 0);
2185 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002186 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002187 else
2188 {
2189 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2190 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002191
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192 /* Guess we are only writing on simple Ethernet header. */
2193 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002194
Ed Warnickecb9cada2015-12-08 15:45:58 -07002195 /* Update packet buffer attributes/set output interface. */
2196 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002197 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002198
Neale Ranns9c6a6132017-02-21 05:33:14 -08002199 if (do_counters)
2200 {
2201 vlib_increment_combined_counter
2202 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002203 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002204 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206
2207 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002208 error0 =
2209 (vlib_buffer_length_in_chain (vm, p0) >
2210 adj0[0].
2211 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2212 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002213
Dave Barachd7cb1b52016-12-09 09:52:16 -05002214 /* Don't adjust the buffer for hop count issue; icmp-error node
2215 * wants to see the IP headerr */
2216 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2217 {
Chris Luke816f3e12016-06-14 16:24:47 -04002218 p0->current_data -= rw_len0;
2219 p0->current_length += rw_len0;
2220
Dave Barachd7cb1b52016-12-09 09:52:16 -05002221 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002222
Dave Barachd7cb1b52016-12-09 09:52:16 -05002223 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2224 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002225
Neale Rannsb069a692017-03-15 12:34:25 -04002226 if (PREDICT_FALSE
2227 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2228 vnet_feature_arc_start (lm->output_feature_arc_index,
2229 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002230 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002231
Neale Ranns5e575b12016-10-03 09:40:25 +01002232 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002233 {
2234 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2235 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002236 if (is_mcast)
2237 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002238 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002239 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002240
Ed Warnickecb9cada2015-12-08 15:45:58 -07002241 p0->error = error_node->errors[error0];
2242
2243 from += 1;
2244 n_left_from -= 1;
2245 to_next += 1;
2246 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002247
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2249 to_next, n_left_to_next,
2250 pi0, next0);
2251 }
2252
2253 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2254 }
2255
2256 /* Need to do trace after rewrites to pick up new packet data. */
2257 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002258 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002259
2260 return frame->n_vectors;
2261}
2262
2263static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002264ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002265 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002267 if (adj_are_counters_enabled ())
2268 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2269 else
2270 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002271}
2272
2273static uword
2274ip6_rewrite_mcast (vlib_main_t * vm,
2275 vlib_node_runtime_t * node, vlib_frame_t * frame)
2276{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002277 if (adj_are_counters_enabled ())
2278 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2279 else
2280 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281}
2282
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002283static uword
2284ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002285 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002286{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002287 if (adj_are_counters_enabled ())
2288 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2289 else
2290 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002291}
2292
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002293static uword
2294ip6_mcast_midchain (vlib_main_t * vm,
2295 vlib_node_runtime_t * node, vlib_frame_t * frame)
2296{
2297 if (adj_are_counters_enabled ())
2298 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2299 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002300 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002301}
2302
Dave Barachd7cb1b52016-12-09 09:52:16 -05002303/* *INDENT-OFF* */
2304VLIB_REGISTER_NODE (ip6_midchain_node) =
2305{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002306 .function = ip6_midchain,
2307 .name = "ip6-midchain",
2308 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002309 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002310 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002311 };
2312/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002313
Dave Barachd7cb1b52016-12-09 09:52:16 -05002314VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002315
Dave Barachd7cb1b52016-12-09 09:52:16 -05002316/* *INDENT-OFF* */
2317VLIB_REGISTER_NODE (ip6_rewrite_node) =
2318{
Neale Rannsf06aea52016-11-29 06:51:37 -08002319 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320 .name = "ip6-rewrite",
2321 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002322 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002323 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002324 .next_nodes =
2325 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002326 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002327 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002328 },
2329};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331
Neale Rannsf06aea52016-11-29 06:51:37 -08002332VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002333
Neale Ranns32e1c012016-11-22 17:07:28 +00002334/* *INDENT-OFF* */
2335VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2336{
2337 .function = ip6_rewrite_mcast,
2338 .name = "ip6-rewrite-mcast",
2339 .vector_size = sizeof (u32),
2340 .format_trace = format_ip6_rewrite_trace,
2341 .sibling_of = "ip6-rewrite",
2342};
2343/* *INDENT-ON* */
2344
2345VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2346
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002347/* *INDENT-OFF* */
2348VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2349{
2350 .function = ip6_mcast_midchain,
2351 .name = "ip6-mcast-midchain",
2352 .vector_size = sizeof (u32),
2353 .format_trace = format_ip6_rewrite_trace,
2354 .sibling_of = "ip6-rewrite",
2355};
2356/* *INDENT-ON* */
2357
2358VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2359
Ole Troan944f5482016-05-24 11:56:58 +02002360/*
2361 * Hop-by-Hop handling
2362 */
Ole Troan944f5482016-05-24 11:56:58 +02002363ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2364
2365#define foreach_ip6_hop_by_hop_error \
2366_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2367_(FORMAT, "incorrectly formatted hop-by-hop options") \
2368_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2369
Neale Ranns32e1c012016-11-22 17:07:28 +00002370/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002371typedef enum
2372{
Ole Troan944f5482016-05-24 11:56:58 +02002373#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2374 foreach_ip6_hop_by_hop_error
2375#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002376 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002377} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002378/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002379
2380/*
2381 * Primary h-b-h handler trace support
2382 * We work pretty hard on the problem for obvious reasons
2383 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002384typedef struct
2385{
Ole Troan944f5482016-05-24 11:56:58 +02002386 u32 next_index;
2387 u32 trace_len;
2388 u8 option_data[256];
2389} ip6_hop_by_hop_trace_t;
2390
2391vlib_node_registration_t ip6_hop_by_hop_node;
2392
Dave Barachd7cb1b52016-12-09 09:52:16 -05002393static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002394#define _(sym,string) string,
2395 foreach_ip6_hop_by_hop_error
2396#undef _
2397};
2398
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302399u8 *
2400format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2401{
2402 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2403 int total_len = va_arg (*args, int);
2404 ip6_hop_by_hop_option_t *opt0, *limit0;
2405 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2406 u8 type0;
2407
2408 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2409 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2410
2411 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2412 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2413
2414 while (opt0 < limit0)
2415 {
2416 type0 = opt0->type;
2417 switch (type0)
2418 {
2419 case 0: /* Pad, just stop */
2420 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2421 break;
2422
2423 default:
2424 if (hm->trace[type0])
2425 {
2426 s = (*hm->trace[type0]) (s, opt0);
2427 }
2428 else
2429 {
2430 s =
2431 format (s, "\n unrecognized option %d length %d", type0,
2432 opt0->length);
2433 }
2434 opt0 =
2435 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2436 sizeof (ip6_hop_by_hop_option_t));
2437 break;
2438 }
2439 }
2440 return s;
2441}
2442
Ole Troan944f5482016-05-24 11:56:58 +02002443static u8 *
2444format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2445{
2446 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2447 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002448 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002449 ip6_hop_by_hop_header_t *hbh0;
2450 ip6_hop_by_hop_option_t *opt0, *limit0;
2451 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2452
2453 u8 type0;
2454
Dave Barachd7cb1b52016-12-09 09:52:16 -05002455 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002456
2457 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002458 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002459
Dave Barachd7cb1b52016-12-09 09:52:16 -05002460 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2461 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002462
Dave Barachd7cb1b52016-12-09 09:52:16 -05002463 while (opt0 < limit0)
2464 {
2465 type0 = opt0->type;
2466 switch (type0)
2467 {
2468 case 0: /* Pad, just stop */
2469 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2470 break;
Ole Troan944f5482016-05-24 11:56:58 +02002471
Dave Barachd7cb1b52016-12-09 09:52:16 -05002472 default:
2473 if (hm->trace[type0])
2474 {
2475 s = (*hm->trace[type0]) (s, opt0);
2476 }
2477 else
2478 {
2479 s =
2480 format (s, "\n unrecognized option %d length %d", type0,
2481 opt0->length);
2482 }
2483 opt0 =
2484 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2485 sizeof (ip6_hop_by_hop_option_t));
2486 break;
2487 }
Ole Troan944f5482016-05-24 11:56:58 +02002488 }
Ole Troan944f5482016-05-24 11:56:58 +02002489 return s;
2490}
2491
Dave Barachd7cb1b52016-12-09 09:52:16 -05002492always_inline u8
2493ip6_scan_hbh_options (vlib_buffer_t * b0,
2494 ip6_header_t * ip0,
2495 ip6_hop_by_hop_header_t * hbh0,
2496 ip6_hop_by_hop_option_t * opt0,
2497 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002498{
2499 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2500 u8 type0;
2501 u8 error0 = 0;
2502
2503 while (opt0 < limit0)
2504 {
2505 type0 = opt0->type;
2506 switch (type0)
2507 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002508 case 0: /* Pad1 */
2509 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002510 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002511 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002512 break;
2513 default:
2514 if (hm->options[type0])
2515 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2517 {
Shwethaa91cbe62016-08-08 15:51:04 +01002518 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002519 return (error0);
2520 }
Shwethaa91cbe62016-08-08 15:51:04 +01002521 }
2522 else
2523 {
2524 /* Unrecognized mandatory option, check the two high order bits */
2525 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2526 {
2527 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2528 break;
2529 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2530 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2531 *next0 = IP_LOOKUP_NEXT_DROP;
2532 break;
2533 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2534 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2535 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002536 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2537 ICMP6_parameter_problem_unrecognized_option,
2538 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002539 break;
2540 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2541 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002542 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002543 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002544 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2545 icmp6_error_set_vnet_buffer (b0,
2546 ICMP6_parameter_problem,
2547 ICMP6_parameter_problem_unrecognized_option,
2548 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002549 }
2550 else
2551 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002552 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002553 }
2554 break;
2555 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002556 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002557 }
2558 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002559 opt0 =
2560 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2561 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002562 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002564}
2565
Ole Troan944f5482016-05-24 11:56:58 +02002566/*
2567 * Process the Hop-by-Hop Options header
2568 */
2569static uword
2570ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002571 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002572{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002573 vlib_node_runtime_t *error_node =
2574 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002575 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2576 u32 n_left_from, *from, *to_next;
2577 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002578
2579 from = vlib_frame_vector_args (frame);
2580 n_left_from = frame->n_vectors;
2581 next_index = node->cached_next_index;
2582
Dave Barachd7cb1b52016-12-09 09:52:16 -05002583 while (n_left_from > 0)
2584 {
2585 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002586
Dave Barachd7cb1b52016-12-09 09:52:16 -05002587 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002588
Dave Barachd7cb1b52016-12-09 09:52:16 -05002589 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002590 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002591 u32 bi0, bi1;
2592 vlib_buffer_t *b0, *b1;
2593 u32 next0, next1;
2594 ip6_header_t *ip0, *ip1;
2595 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2596 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2597 u8 error0 = 0, error1 = 0;
2598
2599 /* Prefetch next iteration. */
2600 {
2601 vlib_buffer_t *p2, *p3;
2602
2603 p2 = vlib_get_buffer (vm, from[2]);
2604 p3 = vlib_get_buffer (vm, from[3]);
2605
2606 vlib_prefetch_buffer_header (p2, LOAD);
2607 vlib_prefetch_buffer_header (p3, LOAD);
2608
2609 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2610 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002611 }
2612
Dave Barachd7cb1b52016-12-09 09:52:16 -05002613 /* Speculatively enqueue b0, b1 to the current next frame */
2614 to_next[0] = bi0 = from[0];
2615 to_next[1] = bi1 = from[1];
2616 from += 2;
2617 to_next += 2;
2618 n_left_from -= 2;
2619 n_left_to_next -= 2;
2620
2621 b0 = vlib_get_buffer (vm, bi0);
2622 b1 = vlib_get_buffer (vm, bi1);
2623
2624 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2625 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002626 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002627 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002628 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002629
2630 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2631 next0 = adj0->lookup_next_index;
2632 next1 = adj1->lookup_next_index;
2633
2634 ip0 = vlib_buffer_get_current (b0);
2635 ip1 = vlib_buffer_get_current (b1);
2636 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2637 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2638 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2639 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2640 limit0 =
2641 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2642 ((hbh0->length + 1) << 3));
2643 limit1 =
2644 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2645 ((hbh1->length + 1) << 3));
2646
2647 /*
2648 * Basic validity checks
2649 */
2650 if ((hbh0->length + 1) << 3 >
2651 clib_net_to_host_u16 (ip0->payload_length))
2652 {
2653 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2654 next0 = IP_LOOKUP_NEXT_DROP;
2655 goto outdual;
2656 }
2657 /* Scan the set of h-b-h options, process ones that we understand */
2658 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2659
2660 if ((hbh1->length + 1) << 3 >
2661 clib_net_to_host_u16 (ip1->payload_length))
2662 {
2663 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2664 next1 = IP_LOOKUP_NEXT_DROP;
2665 goto outdual;
2666 }
2667 /* Scan the set of h-b-h options, process ones that we understand */
2668 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2669
2670 outdual:
2671 /* Has the classifier flagged this buffer for special treatment? */
2672 if (PREDICT_FALSE
2673 ((error0 == 0)
2674 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2675 next0 = hm->next_override;
2676
2677 /* Has the classifier flagged this buffer for special treatment? */
2678 if (PREDICT_FALSE
2679 ((error1 == 0)
2680 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2681 next1 = hm->next_override;
2682
2683 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2684 {
2685 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2686 {
2687 ip6_hop_by_hop_trace_t *t =
2688 vlib_add_trace (vm, node, b0, sizeof (*t));
2689 u32 trace_len = (hbh0->length + 1) << 3;
2690 t->next_index = next0;
2691 /* Capture the h-b-h option verbatim */
2692 trace_len =
2693 trace_len <
2694 ARRAY_LEN (t->option_data) ? trace_len :
2695 ARRAY_LEN (t->option_data);
2696 t->trace_len = trace_len;
2697 clib_memcpy (t->option_data, hbh0, trace_len);
2698 }
2699 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2700 {
2701 ip6_hop_by_hop_trace_t *t =
2702 vlib_add_trace (vm, node, b1, sizeof (*t));
2703 u32 trace_len = (hbh1->length + 1) << 3;
2704 t->next_index = next1;
2705 /* Capture the h-b-h option verbatim */
2706 trace_len =
2707 trace_len <
2708 ARRAY_LEN (t->option_data) ? trace_len :
2709 ARRAY_LEN (t->option_data);
2710 t->trace_len = trace_len;
2711 clib_memcpy (t->option_data, hbh1, trace_len);
2712 }
2713
2714 }
2715
2716 b0->error = error_node->errors[error0];
2717 b1->error = error_node->errors[error1];
2718
2719 /* verify speculative enqueue, maybe switch current next frame */
2720 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2721 n_left_to_next, bi0, bi1, next0,
2722 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002723 }
2724
Dave Barachd7cb1b52016-12-09 09:52:16 -05002725 while (n_left_from > 0 && n_left_to_next > 0)
2726 {
2727 u32 bi0;
2728 vlib_buffer_t *b0;
2729 u32 next0;
2730 ip6_header_t *ip0;
2731 ip6_hop_by_hop_header_t *hbh0;
2732 ip6_hop_by_hop_option_t *opt0, *limit0;
2733 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002734
Dave Barachd7cb1b52016-12-09 09:52:16 -05002735 /* Speculatively enqueue b0 to the current next frame */
2736 bi0 = from[0];
2737 to_next[0] = bi0;
2738 from += 1;
2739 to_next += 1;
2740 n_left_from -= 1;
2741 n_left_to_next -= 1;
2742
2743 b0 = vlib_get_buffer (vm, bi0);
2744 /*
2745 * Default use the next_index from the adjacency.
2746 * A HBH option rarely redirects to a different node
2747 */
2748 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002749 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002750 next0 = adj0->lookup_next_index;
2751
2752 ip0 = vlib_buffer_get_current (b0);
2753 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2754 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2755 limit0 =
2756 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2757 ((hbh0->length + 1) << 3));
2758
2759 /*
2760 * Basic validity checks
2761 */
2762 if ((hbh0->length + 1) << 3 >
2763 clib_net_to_host_u16 (ip0->payload_length))
2764 {
2765 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2766 next0 = IP_LOOKUP_NEXT_DROP;
2767 goto out0;
2768 }
2769
2770 /* Scan the set of h-b-h options, process ones that we understand */
2771 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2772
2773 out0:
2774 /* Has the classifier flagged this buffer for special treatment? */
2775 if (PREDICT_FALSE
2776 ((error0 == 0)
2777 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2778 next0 = hm->next_override;
2779
2780 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2781 {
2782 ip6_hop_by_hop_trace_t *t =
2783 vlib_add_trace (vm, node, b0, sizeof (*t));
2784 u32 trace_len = (hbh0->length + 1) << 3;
2785 t->next_index = next0;
2786 /* Capture the h-b-h option verbatim */
2787 trace_len =
2788 trace_len <
2789 ARRAY_LEN (t->option_data) ? trace_len :
2790 ARRAY_LEN (t->option_data);
2791 t->trace_len = trace_len;
2792 clib_memcpy (t->option_data, hbh0, trace_len);
2793 }
2794
2795 b0->error = error_node->errors[error0];
2796
2797 /* verify speculative enqueue, maybe switch current next frame */
2798 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2799 n_left_to_next, bi0, next0);
2800 }
2801 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002802 }
Ole Troan944f5482016-05-24 11:56:58 +02002803 return frame->n_vectors;
2804}
2805
Dave Barachd7cb1b52016-12-09 09:52:16 -05002806/* *INDENT-OFF* */
2807VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2808{
Ole Troan944f5482016-05-24 11:56:58 +02002809 .function = ip6_hop_by_hop,
2810 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002811 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002812 .vector_size = sizeof (u32),
2813 .format_trace = format_ip6_hop_by_hop_trace,
2814 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002815 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002816 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002817 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002818};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002819/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002820
Dave Barach5331c722016-08-17 11:54:30 -04002821VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002822
2823static clib_error_t *
2824ip6_hop_by_hop_init (vlib_main_t * vm)
2825{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002826 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2827 memset (hm->options, 0, sizeof (hm->options));
2828 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002829 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002830 return (0);
2831}
2832
2833VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2834
Dave Barachd7cb1b52016-12-09 09:52:16 -05002835void
2836ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002837{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002838 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002839
2840 hm->next_override = next;
2841}
2842
Ole Troan944f5482016-05-24 11:56:58 +02002843int
2844ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002845 int options (vlib_buffer_t * b, ip6_header_t * ip,
2846 ip6_hop_by_hop_option_t * opt),
2847 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002848{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002849 ip6_main_t *im = &ip6_main;
2850 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002851
2852 ASSERT (option < ARRAY_LEN (hm->options));
2853
2854 /* Already registered */
2855 if (hm->options[option])
2856 return (-1);
2857
2858 hm->options[option] = options;
2859 hm->trace[option] = trace;
2860
2861 /* Set global variable */
2862 im->hbh_enabled = 1;
2863
2864 return (0);
2865}
2866
2867int
2868ip6_hbh_unregister_option (u8 option)
2869{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002870 ip6_main_t *im = &ip6_main;
2871 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002872
2873 ASSERT (option < ARRAY_LEN (hm->options));
2874
2875 /* Not registered */
2876 if (!hm->options[option])
2877 return (-1);
2878
2879 hm->options[option] = NULL;
2880 hm->trace[option] = NULL;
2881
2882 /* Disable global knob if this was the last option configured */
2883 int i;
2884 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002885 for (i = 0; i < 256; i++)
2886 {
2887 if (hm->options[option])
2888 {
2889 found = true;
2890 break;
2891 }
Ole Troan944f5482016-05-24 11:56:58 +02002892 }
Ole Troan944f5482016-05-24 11:56:58 +02002893 if (!found)
2894 im->hbh_enabled = 0;
2895
2896 return (0);
2897}
2898
Ed Warnickecb9cada2015-12-08 15:45:58 -07002899/* Global IP6 main. */
2900ip6_main_t ip6_main;
2901
2902static clib_error_t *
2903ip6_lookup_init (vlib_main_t * vm)
2904{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002905 ip6_main_t *im = &ip6_main;
2906 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002907 uword i;
2908
Damjan Marion8b3191e2016-11-09 19:54:20 +01002909 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2910 return error;
2911
Ed Warnickecb9cada2015-12-08 15:45:58 -07002912 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2913 {
2914 u32 j, i0, i1;
2915
2916 i0 = i / 32;
2917 i1 = i % 32;
2918
2919 for (j = 0; j < i0; j++)
2920 im->fib_masks[i].as_u32[j] = ~0;
2921
2922 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002923 im->fib_masks[i].as_u32[i0] =
2924 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002925 }
2926
2927 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2928
2929 if (im->lookup_table_nbuckets == 0)
2930 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2931
Dave Barachd7cb1b52016-12-09 09:52:16 -05002932 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002933
2934 if (im->lookup_table_size == 0)
2935 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002936
Dave Barachd7cb1b52016-12-09 09:52:16 -05002937 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2938 "ip6 FIB fwding table",
2939 im->lookup_table_nbuckets, im->lookup_table_size);
2940 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2941 "ip6 FIB non-fwding table",
2942 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002943
Ed Warnickecb9cada2015-12-08 15:45:58 -07002944 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002945 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002946 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002947
2948 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002949 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002950 pn = pg_get_node (ip6_lookup_node.index);
2951 pn->unformat_edit = unformat_pg_ip6_header;
2952 }
2953
Ole Troan944f5482016-05-24 11:56:58 +02002954 /* Unless explicitly configured, don't process HBH options */
2955 im->hbh_enabled = 0;
2956
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957 {
2958 icmp6_neighbor_solicitation_header_t p;
2959
2960 memset (&p, 0, sizeof (p));
2961
Dave Barachd7cb1b52016-12-09 09:52:16 -05002962 p.ip.ip_version_traffic_class_and_flow_label =
2963 clib_host_to_net_u32 (0x6 << 28);
2964 p.ip.payload_length =
2965 clib_host_to_net_u16 (sizeof (p) -
2966 STRUCT_OFFSET_OF
2967 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968 p.ip.protocol = IP_PROTOCOL_ICMP6;
2969 p.ip.hop_limit = 255;
2970 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2971
2972 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2973
Dave Barachd7cb1b52016-12-09 09:52:16 -05002974 p.link_layer_option.header.type =
2975 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2976 p.link_layer_option.header.n_data_u64s =
2977 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002978
2979 vlib_packet_template_init (vm,
2980 &im->discover_neighbor_packet_template,
2981 &p, sizeof (p),
2982 /* alloc chunk size */ 8,
2983 "ip6 neighbor discovery");
2984 }
2985
Dave Barach203c6322016-06-26 10:29:03 -04002986 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987}
2988
2989VLIB_INIT_FUNCTION (ip6_lookup_init);
2990
2991static clib_error_t *
2992add_del_ip6_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002993 unformat_input_t * input,
2994 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002995{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002996 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002997 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002998 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999 u32 sw_if_index, table_id;
3000
3001 sw_if_index = ~0;
3002
Dave Barachd7cb1b52016-12-09 09:52:16 -05003003 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07003004 {
3005 error = clib_error_return (0, "unknown interface `%U'",
3006 format_unformat_error, input);
3007 goto done;
3008 }
3009
3010 if (unformat (input, "%d", &table_id))
3011 ;
3012 else
3013 {
3014 error = clib_error_return (0, "expected table id `%U'",
3015 format_unformat_error, input);
3016 goto done;
3017 }
3018
Neale Ranns4008ac92017-02-13 23:20:04 -08003019 /*
3020 * If the interface already has in IP address, then a change int
3021 * VRF is not allowed. The IP address applied must first be removed.
3022 * We do not do that automatically here, since VPP has no knowledge
3023 * of whether thoses subnets are valid in the destination VRF.
3024 */
3025 /* *INDENT-OFF* */
3026 foreach_ip_interface_address (&ip6_main.lookup_main,
3027 ia, sw_if_index,
3028 1 /* honor unnumbered */,
3029 ({
3030 ip4_address_t * a;
3031
3032 a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
3033 error = clib_error_return (0, "interface %U has address %U",
3034 format_vnet_sw_if_index_name, vnm,
3035 sw_if_index,
3036 format_ip6_address, a);
3037 goto done;
3038 }));
3039 /* *INDENT-ON* */
3040
Ed Warnickecb9cada2015-12-08 15:45:58 -07003041 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003042 u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3043 table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003044
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003045 vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
3046 ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00003047
3048 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3049 table_id);
3050
3051 vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
3052 ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003053 }
3054
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003055
Dave Barachd7cb1b52016-12-09 09:52:16 -05003056done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057 return error;
3058}
3059
Billy McFall0683c9c2016-10-13 08:27:31 -04003060/*?
3061 * Place the indicated interface into the supplied IPv6 FIB table (also known
3062 * as a VRF). If the FIB table does not exist, this command creates it. To
3063 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3064 * FIB table will only be displayed if a route has been added to the table, or
3065 * an IP Address is assigned to an interface in the table (which adds a route
3066 * automatically).
3067 *
Neale Ranns4008ac92017-02-13 23:20:04 -08003068 * @note IP addresses added after setting the interface IP table are added to
3069 * the indicated FIB table. If an IP address is added prior to changing the
3070 * table then this is an error. The control plane must remove these addresses
3071 * first and then change the table. VPP will not automatically move the
3072 * addresses from the old to the new table as it does not know the validity
3073 * of such a change.
Billy McFall0683c9c2016-10-13 08:27:31 -04003074 *
3075 * @cliexpar
3076 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3077 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3078 ?*/
3079/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003080VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3081{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003082 .path = "set interface ip6 table",
3083 .function = add_del_ip6_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04003084 .short_help = "set interface ip6 table <interface> <table-id>"
Ed Warnickecb9cada2015-12-08 15:45:58 -07003085};
Billy McFall0683c9c2016-10-13 08:27:31 -04003086/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087
Dave Barach75fc8542016-10-11 16:16:02 -04003088void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3090 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091{
3092 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3093 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003094 ip->as_u8[8] = mac[0] ^ (1 << 1);
3095 ip->as_u8[9] = mac[1];
3096 ip->as_u8[10] = mac[2];
3097 ip->as_u8[11] = 0xFF;
3098 ip->as_u8[12] = 0xFE;
3099 ip->as_u8[13] = mac[3];
3100 ip->as_u8[14] = mac[4];
3101 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102}
3103
Dave Barach75fc8542016-10-11 16:16:02 -04003104void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003105ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3106 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003107{
3108 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003109 mac[0] = ip->as_u8[8] ^ (1 << 1);
3110 mac[1] = ip->as_u8[9];
3111 mac[2] = ip->as_u8[10];
3112 mac[3] = ip->as_u8[13];
3113 mac[4] = ip->as_u8[14];
3114 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003115}
3116
Dave Barach75fc8542016-10-11 16:16:02 -04003117static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003118test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120{
3121 u8 mac[6];
3122 ip6_address_t _a, *a = &_a;
3123
3124 if (unformat (input, "%U", unformat_ethernet_address, mac))
3125 {
3126 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003127 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003128 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3129 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003130 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003131 }
Dave Barach75fc8542016-10-11 16:16:02 -04003132
Ed Warnickecb9cada2015-12-08 15:45:58 -07003133 return 0;
3134}
3135
Billy McFall0683c9c2016-10-13 08:27:31 -04003136/*?
3137 * This command converts the given MAC Address into an IPv6 link-local
3138 * address.
3139 *
3140 * @cliexpar
3141 * Example of how to create an IPv6 link-local address:
3142 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3143 * Link local address: fe80::14d9:e0ff:fe91:7986
3144 * Original MAC address: 16:d9:e0:91:79:86
3145 * @cliexend
3146?*/
3147/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003148VLIB_CLI_COMMAND (test_link_command, static) =
3149{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003151 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003152 .short_help = "test ip6 link <mac-address>",
3153};
Billy McFall0683c9c2016-10-13 08:27:31 -04003154/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155
Dave Barachd7cb1b52016-12-09 09:52:16 -05003156int
3157vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003158{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003159 ip6_fib_t *fib;
Neale Ranns107e7d42017-04-11 09:55:19 -07003160 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003161
Neale Ranns107e7d42017-04-11 09:55:19 -07003162 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163
Neale Ranns107e7d42017-04-11 09:55:19 -07003164 if (~0 == fib_index)
3165 return VNET_API_ERROR_NO_SUCH_FIB;
3166
3167 fib = ip6_fib_get (fib_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003168
3169 fib->flow_hash_config = flow_hash_config;
3170 return 1;
3171}
3172
3173static clib_error_t *
3174set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003175 unformat_input_t * input,
3176 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003177{
3178 int matched = 0;
3179 u32 table_id = 0;
3180 u32 flow_hash_config = 0;
3181 int rv;
3182
Dave Barachd7cb1b52016-12-09 09:52:16 -05003183 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3184 {
3185 if (unformat (input, "table %d", &table_id))
3186 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003187#define _(a,v) \
3188 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003189 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003190#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003191 else
3192 break;
3193 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003194
3195 if (matched == 0)
3196 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003197 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003198
Ed Warnickecb9cada2015-12-08 15:45:58 -07003199 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3200 switch (rv)
3201 {
3202 case 1:
3203 break;
3204
3205 case -1:
3206 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003207
Ed Warnickecb9cada2015-12-08 15:45:58 -07003208 default:
3209 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3210 break;
3211 }
Dave Barach75fc8542016-10-11 16:16:02 -04003212
Ed Warnickecb9cada2015-12-08 15:45:58 -07003213 return 0;
3214}
3215
Billy McFall0683c9c2016-10-13 08:27:31 -04003216/*?
3217 * Configure the set of IPv6 fields used by the flow hash.
3218 *
3219 * @cliexpar
3220 * @parblock
3221 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003222 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3223 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003224 * Example of display the configured flow hash:
3225 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003226 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3227 * @::/0
3228 * unicast-ip6-chain
3229 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3230 * [0] [@0]: dpo-drop ip6
3231 * fe80::/10
3232 * unicast-ip6-chain
3233 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3234 * [0] [@2]: dpo-receive
3235 * ff02::1/128
3236 * unicast-ip6-chain
3237 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3238 * [0] [@2]: dpo-receive
3239 * ff02::2/128
3240 * unicast-ip6-chain
3241 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3242 * [0] [@2]: dpo-receive
3243 * ff02::16/128
3244 * unicast-ip6-chain
3245 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3246 * [0] [@2]: dpo-receive
3247 * ff02::1:ff00:0/104
3248 * unicast-ip6-chain
3249 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3250 * [0] [@2]: dpo-receive
3251 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3252 * @::/0
3253 * unicast-ip6-chain
3254 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3255 * [0] [@0]: dpo-drop ip6
3256 * @::a:1:1:0:4/126
3257 * unicast-ip6-chain
3258 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3259 * [0] [@4]: ipv6-glean: af_packet0
3260 * @::a:1:1:0:7/128
3261 * unicast-ip6-chain
3262 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3263 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3264 * fe80::/10
3265 * unicast-ip6-chain
3266 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3267 * [0] [@2]: dpo-receive
3268 * fe80::fe:3eff:fe3e:9222/128
3269 * unicast-ip6-chain
3270 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3271 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3272 * ff02::1/128
3273 * unicast-ip6-chain
3274 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3275 * [0] [@2]: dpo-receive
3276 * ff02::2/128
3277 * unicast-ip6-chain
3278 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3279 * [0] [@2]: dpo-receive
3280 * ff02::16/128
3281 * unicast-ip6-chain
3282 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3283 * [0] [@2]: dpo-receive
3284 * ff02::1:ff00:0/104
3285 * unicast-ip6-chain
3286 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3287 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003288 * @cliexend
3289 * @endparblock
3290?*/
3291/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003292VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3293{
3294 .path = "set ip6 flow-hash",
3295 .short_help =
3296 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3297 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003298};
Billy McFall0683c9c2016-10-13 08:27:31 -04003299/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003300
3301static clib_error_t *
3302show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003303 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003304{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003305 ip6_main_t *im = &ip6_main;
3306 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003307 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003308
Ed Warnickecb9cada2015-12-08 15:45:58 -07003309 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003310 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003311 {
3312 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003313 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003314 }
3315 return 0;
3316}
3317
3318
3319
Billy McFall0683c9c2016-10-13 08:27:31 -04003320/*?
3321 * Display the set of protocols handled by the local IPv6 stack.
3322 *
3323 * @cliexpar
3324 * Example of how to display local protocol table:
3325 * @cliexstart{show ip6 local}
3326 * Protocols handled by ip6_local
3327 * 17
3328 * 43
3329 * 58
3330 * 115
3331 * @cliexend
3332?*/
3333/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003334VLIB_CLI_COMMAND (show_ip6_local, static) =
3335{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003336 .path = "show ip6 local",
3337 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003338 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003339};
Billy McFall0683c9c2016-10-13 08:27:31 -04003340/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003341
Dave Barachd7cb1b52016-12-09 09:52:16 -05003342int
3343vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3344 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003345{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003346 vnet_main_t *vnm = vnet_get_main ();
3347 vnet_interface_main_t *im = &vnm->interface_main;
3348 ip6_main_t *ipm = &ip6_main;
3349 ip_lookup_main_t *lm = &ipm->lookup_main;
3350 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003351 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003352
3353 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3354 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3355
3356 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3357 return VNET_API_ERROR_NO_SUCH_ENTRY;
3358
3359 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003360 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003361
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003362 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003363
3364 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003365 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003366 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003367 .fp_len = 128,
3368 .fp_proto = FIB_PROTOCOL_IP6,
3369 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003370 };
3371 u32 fib_index;
3372
Dave Barachd7cb1b52016-12-09 09:52:16 -05003373 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3374 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003375
3376
Dave Barachd7cb1b52016-12-09 09:52:16 -05003377 if (table_index != (u32) ~ 0)
3378 {
3379 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003380
Dave Barachd7cb1b52016-12-09 09:52:16 -05003381 dpo_set (&dpo,
3382 DPO_CLASSIFY,
3383 DPO_PROTO_IP6,
3384 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003385
Dave Barachd7cb1b52016-12-09 09:52:16 -05003386 fib_table_entry_special_dpo_add (fib_index,
3387 &pfx,
3388 FIB_SOURCE_CLASSIFY,
3389 FIB_ENTRY_FLAG_NONE, &dpo);
3390 dpo_reset (&dpo);
3391 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003392 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003393 {
3394 fib_table_entry_special_remove (fib_index,
3395 &pfx, FIB_SOURCE_CLASSIFY);
3396 }
3397 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003398
Ed Warnickecb9cada2015-12-08 15:45:58 -07003399 return 0;
3400}
3401
3402static clib_error_t *
3403set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003404 unformat_input_t * input,
3405 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003406{
3407 u32 table_index = ~0;
3408 int table_index_set = 0;
3409 u32 sw_if_index = ~0;
3410 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003411
Dave Barachd7cb1b52016-12-09 09:52:16 -05003412 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3413 {
3414 if (unformat (input, "table-index %d", &table_index))
3415 table_index_set = 1;
3416 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3417 vnet_get_main (), &sw_if_index))
3418 ;
3419 else
3420 break;
3421 }
Dave Barach75fc8542016-10-11 16:16:02 -04003422
Ed Warnickecb9cada2015-12-08 15:45:58 -07003423 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003424 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003425
Ed Warnickecb9cada2015-12-08 15:45:58 -07003426 if (sw_if_index == ~0)
3427 return clib_error_return (0, "interface / subif must be specified");
3428
3429 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3430
3431 switch (rv)
3432 {
3433 case 0:
3434 break;
3435
3436 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3437 return clib_error_return (0, "No such interface");
3438
3439 case VNET_API_ERROR_NO_SUCH_ENTRY:
3440 return clib_error_return (0, "No such classifier table");
3441 }
3442 return 0;
3443}
3444
Billy McFall0683c9c2016-10-13 08:27:31 -04003445/*?
3446 * Assign a classification table to an interface. The classification
3447 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3448 * commands. Once the table is create, use this command to filter packets
3449 * on an interface.
3450 *
3451 * @cliexpar
3452 * Example of how to assign a classification table to an interface:
3453 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3454?*/
3455/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003456VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3457{
3458 .path = "set ip6 classify",
3459 .short_help =
3460 "set ip6 classify intfc <interface> table-index <classify-idx>",
3461 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003462};
Billy McFall0683c9c2016-10-13 08:27:31 -04003463/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003464
3465static clib_error_t *
3466ip6_config (vlib_main_t * vm, unformat_input_t * input)
3467{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003468 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003469 uword heapsize = 0;
3470 u32 tmp;
3471 u32 nbuckets = 0;
3472
Dave Barachd7cb1b52016-12-09 09:52:16 -05003473 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3474 {
3475 if (unformat (input, "hash-buckets %d", &tmp))
3476 nbuckets = tmp;
3477 else if (unformat (input, "heap-size %dm", &tmp))
3478 heapsize = ((u64) tmp) << 20;
3479 else if (unformat (input, "heap-size %dM", &tmp))
3480 heapsize = ((u64) tmp) << 20;
3481 else if (unformat (input, "heap-size %dg", &tmp))
3482 heapsize = ((u64) tmp) << 30;
3483 else if (unformat (input, "heap-size %dG", &tmp))
3484 heapsize = ((u64) tmp) << 30;
3485 else
3486 return clib_error_return (0, "unknown input '%U'",
3487 format_unformat_error, input);
3488 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003489
3490 im->lookup_table_nbuckets = nbuckets;
3491 im->lookup_table_size = heapsize;
3492
3493 return 0;
3494}
3495
3496VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003497
3498/*
3499 * fd.io coding-style-patch-verification: ON
3500 *
3501 * Local Variables:
3502 * eval: (c-set-style "gnu")
3503 * End:
3504 */