blob: 6b89ec38aae3069788f0df14261b1816621eb25f [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
AkshayaNadahallied4a2fd2016-08-09 13:38:04 +05302 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip6_forward.c: IP v6 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +020042#include <vnet/ip/ip6_neighbor.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
45#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053046#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000048#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070049#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/bihash_template.c>
53
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053054/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
55#define OI_DECAP 0x80000000
56
Billy McFall0683c9c2016-10-13 08:27:31 -040057/**
58 * @file
59 * @brief IPv6 Forwarding.
60 *
61 * This file contains the source code for IPv6 forwarding.
62 */
63
Pierre Pfister0febaf12016-06-08 12:23:21 +010064
Damjan Marionaca64c92016-04-13 09:48:56 +020065always_inline uword
66ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050067 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barachd7cb1b52016-12-09 09:52:16 -050069 ip6_main_t *im = &ip6_main;
70 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
71 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020073 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070074
75 from = vlib_frame_vector_args (frame);
76 n_left_from = frame->n_vectors;
77 next = node->cached_next_index;
78
79 while (n_left_from > 0)
80 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050081 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
83 while (n_left_from >= 4 && n_left_to_next >= 2)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010086 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050088 ip6_header_t *ip0, *ip1;
89 ip6_address_t *dst_addr0, *dst_addr1;
90 u32 fib_index0, fib_index1;
91 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010092 const dpo_id_t *dpo0, *dpo1;
93 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
95 /* Prefetch next iteration. */
96 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050097 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 p2 = vlib_get_buffer (vm, from[2]);
100 p3 = vlib_get_buffer (vm, from[3]);
101
102 vlib_prefetch_buffer_header (p2, LOAD);
103 vlib_prefetch_buffer_header (p3, LOAD);
104 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
105 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
106 }
107
108 pi0 = to_next[0] = from[0];
109 pi1 = to_next[1] = from[1];
110
111 p0 = vlib_get_buffer (vm, pi0);
112 p1 = vlib_get_buffer (vm, pi1);
113
114 ip0 = vlib_buffer_get_current (p0);
115 ip1 = vlib_buffer_get_current (p1);
116
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100117 dst_addr0 = &ip0->dst_address;
118 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200119
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 fib_index0 =
121 vec_elt (im->fib_index_by_sw_if_index,
122 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
123 fib_index1 =
124 vec_elt (im->fib_index_by_sw_if_index,
125 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
128 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
129 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
130 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
133 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100135 lb0 = load_balance_get (lbi0);
136 lb1 = load_balance_get (lbi1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700137 ASSERT (lb0->lb_n_buckets > 0);
138 ASSERT (lb1->lb_n_buckets > 0);
139 ASSERT (is_pow2 (lb0->lb_n_buckets));
140 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
Dave Barachd7cb1b52016-12-09 09:52:16 -0500144 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
145 {
146 flow_hash_config0 = lb0->lb_hash_config;
147 vnet_buffer (p0)->ip.flow_hash =
148 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700149 dpo0 =
150 load_balance_get_fwd_bucket (lb0,
151 (vnet_buffer (p0)->ip.flow_hash &
152 (lb0->lb_n_buckets_minus_1)));
153 }
154 else
155 {
156 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500157 }
158 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
159 {
160 flow_hash_config1 = lb1->lb_hash_config;
161 vnet_buffer (p1)->ip.flow_hash =
162 ip6_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700163 dpo1 =
164 load_balance_get_fwd_bucket (lb1,
165 (vnet_buffer (p1)->ip.flow_hash &
166 (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500167 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700168 else
169 {
170 dpo1 = load_balance_get_bucket_i (lb1, 0);
171 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100172 next0 = dpo0->dpoi_next_node;
173 next1 = dpo1->dpoi_next_node;
174
175 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 if (PREDICT_FALSE
177 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100178 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500179 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100180 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
181 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 if (PREDICT_FALSE
183 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100184 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500185 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100186 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
187 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100188 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
189 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barach75fc8542016-10-11 16:16:02 -0400191 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200192 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400193 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200194 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
196 from += 2;
197 to_next += 2;
198 n_left_to_next -= 2;
199 n_left_from -= 2;
200
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500203 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 switch (wrong_next)
205 {
206 case 1:
207 /* A B A */
208 to_next[-2] = pi1;
209 to_next -= 1;
210 n_left_to_next += 1;
211 vlib_set_next_frame_buffer (vm, node, next0, pi0);
212 break;
213
214 case 2:
215 /* A A B */
216 to_next -= 1;
217 n_left_to_next += 1;
218 vlib_set_next_frame_buffer (vm, node, next1, pi1);
219 break;
220
221 case 3:
222 /* A B C */
223 to_next -= 2;
224 n_left_to_next += 2;
225 vlib_set_next_frame_buffer (vm, node, next0, pi0);
226 vlib_set_next_frame_buffer (vm, node, next1, pi1);
227 if (next0 == next1)
228 {
229 /* A B B */
230 vlib_put_next_frame (vm, node, next, n_left_to_next);
231 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500232 vlib_get_next_frame (vm, node, next, to_next,
233 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 }
235 }
236 }
237 }
Dave Barach75fc8542016-10-11 16:16:02 -0400238
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 while (n_left_from > 0 && n_left_to_next > 0)
240 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500241 vlib_buffer_t *p0;
242 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100243 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500245 load_balance_t *lb0;
246 ip6_address_t *dst_addr0;
247 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249
250 pi0 = from[0];
251 to_next[0] = pi0;
252
253 p0 = vlib_get_buffer (vm, pi0);
254
255 ip0 = vlib_buffer_get_current (p0);
256
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200258
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 fib_index0 =
260 vec_elt (im->fib_index_by_sw_if_index,
261 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
262 fib_index0 =
263 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
264 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100266 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100268 lb0 = load_balance_get (lbi0);
Neale Ranns227038a2017-04-21 01:07:59 -0700269 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270
Dave Barachd7cb1b52016-12-09 09:52:16 -0500271 vnet_buffer (p0)->ip.flow_hash = 0;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700272 ASSERT (lb0->lb_n_buckets > 0);
273 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274
Dave Barachd7cb1b52016-12-09 09:52:16 -0500275 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
276 {
277 flow_hash_config0 = lb0->lb_hash_config;
278 vnet_buffer (p0)->ip.flow_hash =
279 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700280 dpo0 =
281 load_balance_get_fwd_bucket (lb0,
282 (vnet_buffer (p0)->ip.flow_hash &
283 (lb0->lb_n_buckets_minus_1)));
284 }
285 else
286 {
287 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500288 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
Dave Barachd7cb1b52016-12-09 09:52:16 -0500290 dpo0 = load_balance_get_bucket_i (lb0,
291 (vnet_buffer (p0)->ip.flow_hash &
292 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100293 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
Shwetha57fc8542016-09-27 08:04:05 +0100295 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500296 if (PREDICT_FALSE
297 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100298 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500299 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100300 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
301 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303
Dave Barach75fc8542016-10-11 16:16:02 -0400304 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200305 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
307 from += 1;
308 to_next += 1;
309 n_left_to_next -= 1;
310 n_left_from -= 1;
311
312 if (PREDICT_FALSE (next0 != next))
313 {
314 n_left_to_next += 1;
315 vlib_put_next_frame (vm, node, next, n_left_to_next);
316 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 to_next[0] = pi0;
319 to_next += 1;
320 n_left_to_next -= 1;
321 }
322 }
323
324 vlib_put_next_frame (vm, node, next, n_left_to_next);
325 }
326
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100327 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500328 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100329
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 return frame->n_vectors;
331}
332
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333static void
334ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
335 ip6_main_t * im, u32 fib_index,
336 ip_interface_address_t * a)
337{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500338 ip_lookup_main_t *lm = &im->lookup_main;
339 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100340 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500341 .fp_len = a->address_length,
342 .fp_proto = FIB_PROTOCOL_IP6,
343 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100344 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 {
Neale Ranns7a272742017-05-30 02:08:14 -0700348 fib_table_entry_update_one_path (fib_index,
349 &pfx,
350 FIB_SOURCE_INTERFACE,
351 (FIB_ENTRY_FLAG_CONNECTED |
352 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700353 DPO_PROTO_IP6,
Neale Ranns7a272742017-05-30 02:08:14 -0700354 /* No next-hop address */
355 NULL, sw_if_index,
356 /* invalid FIB index */
357 ~0, 1,
358 /* no label stack */
359 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500360 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500364 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100365 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500366 lm->classify_table_index_by_sw_if_index[sw_if_index];
367 if (classify_table_index != (u32) ~ 0)
368 {
369 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370
Dave Barachd7cb1b52016-12-09 09:52:16 -0500371 dpo_set (&dpo,
372 DPO_CLASSIFY,
373 DPO_PROTO_IP6,
374 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 fib_table_entry_special_dpo_add (fib_index,
377 &pfx,
378 FIB_SOURCE_CLASSIFY,
379 FIB_ENTRY_FLAG_NONE, &dpo);
380 dpo_reset (&dpo);
381 }
382 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100383
Neale Rannsf12a83f2017-04-18 09:09:40 -0700384 fib_table_entry_update_one_path (fib_index, &pfx,
385 FIB_SOURCE_INTERFACE,
386 (FIB_ENTRY_FLAG_CONNECTED |
387 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700388 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700389 &pfx.fp_addr,
390 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500391 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392}
393
394static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100395ip6_del_interface_routes (ip6_main_t * im,
396 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500397 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500399 fib_prefix_t pfx = {
400 .fp_len = address_length,
401 .fp_proto = FIB_PROTOCOL_IP6,
402 .fp_addr.ip6 = *address,
403 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404
Dave Barachd7cb1b52016-12-09 09:52:16 -0500405 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500407 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100408
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 }
410
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 pfx.fp_len = 128;
412 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413}
414
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100415void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500418 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100420 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422 /*
423 * enable/disable only on the 1<->0 transition
424 */
425 if (is_enable)
426 {
427 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500428 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 }
430 else
431 {
Neale Ranns75152282017-01-09 01:00:45 -0800432 /* The ref count is 0 when an address is removed from an interface that has
433 * no address - this is not a ciritical error */
434 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
435 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500436 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100437 }
438
Neale Ranns630198f2017-05-22 09:20:20 -0400439 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
440 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100441
Neale Ranns630198f2017-05-22 09:20:20 -0400442 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
443 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444}
445
Neale Rannsdf089a82016-10-02 16:39:06 +0100446/* get first interface address */
447ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800448ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100449{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500450 ip_lookup_main_t *lm = &im->lookup_main;
451 ip_interface_address_t *ia = 0;
452 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100453
Dave Barachd7cb1b52016-12-09 09:52:16 -0500454 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100455 foreach_ip_interface_address (lm, ia, sw_if_index,
456 1 /* honor unnumbered */,
457 ({
458 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
459 result = a;
460 break;
461 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100463 return result;
464}
465
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466clib_error_t *
467ip6_add_del_interface_address (vlib_main_t * vm,
468 u32 sw_if_index,
469 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500470 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 vnet_main_t *vnm = vnet_get_main ();
473 ip6_main_t *im = &ip6_main;
474 ip_lookup_main_t *lm = &im->lookup_main;
475 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478
Pavel Kotucek57808982017-08-02 08:20:19 +0200479 /* local0 interface doesn't support IP addressing */
480 if (sw_if_index == 0)
481 {
482 return
483 clib_error_create ("local0 interface doesn't support IP addressing");
484 }
485
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000487 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
488
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489 ip6_addr_fib_init (&ip6_af, address,
490 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
491 vec_add1 (addr_fib, ip6_af);
492
493 {
494 uword elts_before = pool_elts (lm->if_address_pool);
495
496 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500497 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 if (error)
499 goto done;
500
501 /* Pool did not grow: add duplicate address. */
502 if (elts_before == pool_elts (lm->if_address_pool))
503 goto done;
504 }
505
Dave Barachd7cb1b52016-12-09 09:52:16 -0500506 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000507
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100508 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100510 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 ip6_add_interface_routes (vnm, sw_if_index,
512 im, ip6_af.fib_index,
513 pool_elt_at_index (lm->if_address_pool,
514 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500517 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518 vec_foreach (cb, im->add_del_interface_address_callbacks)
519 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 }
522
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 vec_free (addr_fib);
525 return error;
526}
527
528clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500531 ip6_main_t *im = &ip6_main;
532 ip_interface_address_t *ia;
533 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 u32 is_admin_up, fib_index;
535
536 /* Fill in lookup tables with default table (0). */
537 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
538
Dave Barachd7cb1b52016-12-09 09:52:16 -0500539 vec_validate_init_empty (im->
540 lookup_main.if_address_pool_index_by_sw_if_index,
541 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542
543 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
544
545 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
546
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400548 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 0 /* honor unnumbered */,
550 ({
551 a = ip_interface_address_get_address (&im->lookup_main, ia);
552 if (is_admin_up)
553 ip6_add_interface_routes (vnm, sw_if_index,
554 im, fib_index,
555 ia);
556 else
557 ip6_del_interface_routes (im, fib_index,
558 a, ia->address_length);
559 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500560 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561
562 return 0;
563}
564
565VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
566
Dave Barachd6534602016-06-14 18:38:02 -0400567/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500568/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100569VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
570{
571 .arc_name = "ip6-unicast",
572 .start_nodes = VNET_FEATURES ("ip6-input"),
573 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
574};
575
Dave Barachd7cb1b52016-12-09 09:52:16 -0500576VNET_FEATURE_INIT (ip6_flow_classify, static) =
577{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100578 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700579 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100580 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700581};
582
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583VNET_FEATURE_INIT (ip6_inacl, static) =
584{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100585 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400586 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100587 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400588};
589
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590VNET_FEATURE_INIT (ip6_policer_classify, static) =
591{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100592 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700593 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100594 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700595};
596
Dave Barachd7cb1b52016-12-09 09:52:16 -0500597VNET_FEATURE_INIT (ip6_ipsec, static) =
598{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100599 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400600 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100601 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400602};
603
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604VNET_FEATURE_INIT (ip6_l2tp, static) =
605{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100606 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400607 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100608 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400609};
610
Dave Barachd7cb1b52016-12-09 09:52:16 -0500611VNET_FEATURE_INIT (ip6_vpath, static) =
612{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100613 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400614 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500615 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
616};
617
618VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
619{
620 .arc_name = "ip6-unicast",
621 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100622 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400623};
624
Dave Barachd7cb1b52016-12-09 09:52:16 -0500625VNET_FEATURE_INIT (ip6_drop, static) =
626{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100627 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400629 .runs_before = VNET_FEATURES ("ip6-lookup"),
630};
631
632VNET_FEATURE_INIT (ip6_lookup, static) =
633{
634 .arc_name = "ip6-unicast",
635 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637};
638
Dave Barachd6534602016-06-14 18:38:02 -0400639/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100640VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
641{
642 .arc_name = "ip6-multicast",
643 .start_nodes = VNET_FEATURES ("ip6-input"),
644 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
645};
646
647VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
648 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400649 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000650 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400651};
652
Damjan Marion8b3191e2016-11-09 19:54:20 +0100653VNET_FEATURE_INIT (ip6_drop_mc, static) = {
654 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100655 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400656 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
657};
658
659VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
660 .arc_name = "ip6-multicast",
661 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100663};
Dave Barach5331c722016-08-17 11:54:30 -0400664
665/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100666VNET_FEATURE_ARC_INIT (ip6_output, static) =
667{
668 .arc_name = "ip6-output",
669 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
670 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400671};
672
Matus Fabian08a6f012016-11-15 06:08:51 -0800673VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
674 .arc_name = "ip6-output",
675 .node_name = "ipsec-output-ip6",
676 .runs_before = VNET_FEATURES ("interface-output"),
677};
678
Damjan Marion8b3191e2016-11-09 19:54:20 +0100679VNET_FEATURE_INIT (ip6_interface_output, static) = {
680 .arc_name = "ip6-output",
681 .node_name = "interface-output",
682 .runs_before = 0, /* not before any other features */
683};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500684/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400685
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700689 ip6_main_t *im = &ip6_main;
690
691 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
692 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
693
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200694 if (!is_add)
695 {
696 /* Ensure that IPv6 is disabled */
697 ip6_main_t *im6 = &ip6_main;
698 ip_lookup_main_t *lm6 = &im6->lookup_main;
699 ip_interface_address_t *ia = 0;
700 ip6_address_t *address;
701 vlib_main_t *vm = vlib_get_main ();
702
703 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
704 /* *INDENT-OFF* */
705 foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* honor unnumbered */,
706 ({
707 address = ip_interface_address_get_address (lm6, ia);
708 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
709 }));
710 /* *INDENT-ON* */
711 ip6_mfib_interface_enable_disable (sw_if_index, 0);
712 }
713
Damjan Marion8b3191e2016-11-09 19:54:20 +0100714 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
715 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Damjan Marion8b3191e2016-11-09 19:54:20 +0100717 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
718 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720 return /* no error */ 0;
721}
722
723VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
724
Damjan Marionaca64c92016-04-13 09:48:56 +0200725static uword
726ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500727 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200728{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100729 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200730}
731
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100733
Dave Barachd7cb1b52016-12-09 09:52:16 -0500734/* *INDENT-OFF* */
735VLIB_REGISTER_NODE (ip6_lookup_node) =
736{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 .function = ip6_lookup,
738 .name = "ip6-lookup",
739 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100740 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200741 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200742 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
Dave Barachd7cb1b52016-12-09 09:52:16 -0500746VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200747
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100748always_inline uword
749ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200751{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500752 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
753 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100754 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200755 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100757
758 from = vlib_frame_vector_args (frame);
759 n_left_from = frame->n_vectors;
760 next = node->cached_next_index;
761
762 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764
765 while (n_left_from > 0)
766 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500767 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100768
Dave Barach75fc8542016-10-11 16:16:02 -0400769
Neale Ranns2be95c12016-11-19 13:50:04 +0000770 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500771 {
772 ip_lookup_next_t next0, next1;
773 const load_balance_t *lb0, *lb1;
774 vlib_buffer_t *p0, *p1;
775 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
776 const ip6_header_t *ip0, *ip1;
777 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000778
Dave Barachd7cb1b52016-12-09 09:52:16 -0500779 /* Prefetch next iteration. */
780 {
781 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000782
Dave Barachd7cb1b52016-12-09 09:52:16 -0500783 p2 = vlib_get_buffer (vm, from[2]);
784 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000785
Dave Barachd7cb1b52016-12-09 09:52:16 -0500786 vlib_prefetch_buffer_header (p2, STORE);
787 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000788
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
790 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
791 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000792
Dave Barachd7cb1b52016-12-09 09:52:16 -0500793 pi0 = to_next[0] = from[0];
794 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000795
Dave Barachd7cb1b52016-12-09 09:52:16 -0500796 from += 2;
797 n_left_from -= 2;
798 to_next += 2;
799 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000800
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 p0 = vlib_get_buffer (vm, pi0);
802 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000803
Dave Barachd7cb1b52016-12-09 09:52:16 -0500804 ip0 = vlib_buffer_get_current (p0);
805 ip1 = vlib_buffer_get_current (p1);
806 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
807 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000808
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 lb0 = load_balance_get (lbi0);
810 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000811
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 /*
813 * this node is for via FIBs we can re-use the hash value from the
814 * to node if present.
815 * We don't want to use the same hash value at each level in the recursion
816 * graph as that would lead to polarisation
817 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000818 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000819
Dave Barachd7cb1b52016-12-09 09:52:16 -0500820 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
821 {
822 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
823 {
824 hc0 = vnet_buffer (p0)->ip.flow_hash =
825 vnet_buffer (p0)->ip.flow_hash >> 1;
826 }
827 else
828 {
829 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000830 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500831 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700832 dpo0 =
833 load_balance_get_fwd_bucket (lb0,
834 (hc0 &
835 lb0->lb_n_buckets_minus_1));
836 }
837 else
838 {
839 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500840 }
841 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
842 {
843 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
844 {
845 hc1 = vnet_buffer (p1)->ip.flow_hash =
846 vnet_buffer (p1)->ip.flow_hash >> 1;
847 }
848 else
849 {
850 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000851 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500852 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700853 dpo1 =
854 load_balance_get_fwd_bucket (lb1,
855 (hc1 &
856 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700858 else
859 {
860 dpo1 = load_balance_get_bucket_i (lb1, 0);
861 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000862
Dave Barachd7cb1b52016-12-09 09:52:16 -0500863 next0 = dpo0->dpoi_next_node;
864 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000865
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866 /* Only process the HBH Option Header if explicitly configured to do so */
867 if (PREDICT_FALSE
868 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
869 {
870 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
871 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
872 }
873 /* Only process the HBH Option Header if explicitly configured to do so */
874 if (PREDICT_FALSE
875 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
876 {
877 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
878 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
879 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000880
Dave Barachd7cb1b52016-12-09 09:52:16 -0500881 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
882 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000883
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200885 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500886 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200887 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000888
Dave Barachd7cb1b52016-12-09 09:52:16 -0500889 vlib_validate_buffer_enqueue_x2 (vm, node, next,
890 to_next, n_left_to_next,
891 pi0, pi1, next0, next1);
892 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000893
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100894 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500895 {
896 ip_lookup_next_t next0;
897 const load_balance_t *lb0;
898 vlib_buffer_t *p0;
899 u32 pi0, lbi0, hc0;
900 const ip6_header_t *ip0;
901 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100902
Dave Barachd7cb1b52016-12-09 09:52:16 -0500903 pi0 = from[0];
904 to_next[0] = pi0;
905 from += 1;
906 to_next += 1;
907 n_left_to_next -= 1;
908 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100909
Dave Barachd7cb1b52016-12-09 09:52:16 -0500910 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100911
Dave Barachd7cb1b52016-12-09 09:52:16 -0500912 ip0 = vlib_buffer_get_current (p0);
913 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100916
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000917 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500918 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
919 {
920 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
921 {
922 hc0 = vnet_buffer (p0)->ip.flow_hash =
923 vnet_buffer (p0)->ip.flow_hash >> 1;
924 }
925 else
926 {
927 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000928 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500929 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700930 dpo0 =
931 load_balance_get_fwd_bucket (lb0,
932 (hc0 &
933 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700935 else
936 {
937 dpo0 = load_balance_get_bucket_i (lb0, 0);
938 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100939
Dave Barachd7cb1b52016-12-09 09:52:16 -0500940 next0 = dpo0->dpoi_next_node;
941 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000942
Dave Barachd7cb1b52016-12-09 09:52:16 -0500943 /* Only process the HBH Option Header if explicitly configured to do so */
944 if (PREDICT_FALSE
945 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
946 {
947 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
948 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
949 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000950
Dave Barachd7cb1b52016-12-09 09:52:16 -0500951 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200952 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100953
Dave Barachd7cb1b52016-12-09 09:52:16 -0500954 vlib_validate_buffer_enqueue_x1 (vm, node, next,
955 to_next, n_left_to_next,
956 pi0, next0);
957 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
959 vlib_put_next_frame (vm, node, next, n_left_to_next);
960 }
961
962 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200963}
964
Dave Barachd7cb1b52016-12-09 09:52:16 -0500965/* *INDENT-OFF* */
966VLIB_REGISTER_NODE (ip6_load_balance_node) =
967{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100968 .function = ip6_load_balance,
969 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200970 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200971 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100972 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200973};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200977
Dave Barachd7cb1b52016-12-09 09:52:16 -0500978typedef struct
979{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 /* Adjacency taken. */
981 u32 adj_index;
982 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500983 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984
985 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986 u8 packet_data[128 - 1 * sizeof (u32)];
987}
988ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
John Lo2b81eb82017-01-30 13:12:10 -0500990u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100993 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
994 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200996 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100997
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998 s = format (s, "%U%U",
999 format_white_space, indent,
1000 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001001 return s;
1002}
1003
Dave Barachd7cb1b52016-12-09 09:52:16 -05001004static u8 *
1005format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001006{
1007 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1008 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001010 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011
John Loac8146c2016-09-27 17:44:02 -04001012 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013 t->fib_index, t->adj_index, t->flow_hash);
1014 s = format (s, "\n%U%U",
1015 format_white_space, indent,
1016 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001017 return s;
1018}
Pierre Pfister0febaf12016-06-08 12:23:21 +01001019
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021static u8 *
1022format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001023{
1024 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1025 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001027 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001029 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001030 t->fib_index, t->adj_index, format_ip_adjacency,
1031 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001032 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033 format_white_space, indent,
1034 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001035 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036 return s;
1037}
1038
1039/* Common trace function for all ip6-forward next nodes. */
1040void
1041ip6_forward_next_trace (vlib_main_t * vm,
1042 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001043 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001045 u32 *from, n_left;
1046 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047
1048 n_left = frame->n_vectors;
1049 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001050
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 while (n_left >= 4)
1052 {
1053 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001054 vlib_buffer_t *b0, *b1;
1055 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
1057 /* Prefetch next iteration. */
1058 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1059 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1060
1061 bi0 = from[0];
1062 bi1 = from[1];
1063
1064 b0 = vlib_get_buffer (vm, bi0);
1065 b1 = vlib_get_buffer (vm, bi1);
1066
1067 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1068 {
1069 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1070 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001071 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1072 t0->fib_index =
1073 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1074 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1075 vec_elt (im->fib_index_by_sw_if_index,
1076 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001077
Damjan Marionf1213b82016-03-13 02:22:06 +01001078 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001079 vlib_buffer_get_current (b0),
1080 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081 }
1082 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1083 {
1084 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1085 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001086 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1087 t1->fib_index =
1088 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1089 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1090 vec_elt (im->fib_index_by_sw_if_index,
1091 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001092
Damjan Marionf1213b82016-03-13 02:22:06 +01001093 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001094 vlib_buffer_get_current (b1),
1095 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 }
1097 from += 2;
1098 n_left -= 2;
1099 }
1100
1101 while (n_left >= 1)
1102 {
1103 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 vlib_buffer_t *b0;
1105 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106
1107 bi0 = from[0];
1108
1109 b0 = vlib_get_buffer (vm, bi0);
1110
1111 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1112 {
1113 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1114 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001115 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1116 t0->fib_index =
1117 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1118 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1119 vec_elt (im->fib_index_by_sw_if_index,
1120 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001121
Damjan Marionf1213b82016-03-13 02:22:06 +01001122 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001123 vlib_buffer_get_current (b0),
1124 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 }
1126 from += 1;
1127 n_left -= 1;
1128 }
1129}
1130
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001132u16
1133ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1134 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135{
1136 ip_csum_t sum0;
1137 u16 sum16, payload_length_host_byte_order;
1138 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 u32 headers_size = sizeof (ip0[0]);
1140 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
Dave Barachd7cb1b52016-12-09 09:52:16 -05001142 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143 *bogus_lengthp = 0;
1144
1145 /* Initialize checksum with ip header. */
1146 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1147 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1148 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001149
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1151 {
1152 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001153 clib_mem_unaligned (&ip0->
1154 src_address.as_uword[i],
1155 uword));
1156 sum0 =
1157 ip_csum_with_carry (sum0,
1158 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1159 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160 }
1161
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301162 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1163 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001164 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001166 u32 skip_bytes;
1167 ip6_hop_by_hop_ext_t *ext_hdr =
1168 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169
1170 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301171 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1172 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
Dave Barachd7cb1b52016-12-09 09:52:16 -05001174 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1175 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001179 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180
1181 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182 if (p0 && n_this_buffer + headers_size > p0->current_length)
1183 n_this_buffer =
1184 p0->current_length >
1185 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186 while (1)
1187 {
1188 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1189 n_bytes_left -= n_this_buffer;
1190 if (n_bytes_left == 0)
1191 break;
1192
1193 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001194 {
1195 *bogus_lengthp = 1;
1196 return 0xfefe;
1197 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 p0 = vlib_get_buffer (vm, p0->next_buffer);
1199 data_this_buffer = vlib_buffer_get_current (p0);
1200 n_this_buffer = p0->current_length;
1201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202
Dave Barachd7cb1b52016-12-09 09:52:16 -05001203 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204
1205 return sum16;
1206}
1207
Dave Barachd7cb1b52016-12-09 09:52:16 -05001208u32
1209ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1212 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 u16 sum16;
1214 int bogus_length;
1215
1216 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1217 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1218 || ip0->protocol == IP_PROTOCOL_ICMP6
1219 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001220 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221
1222 udp0 = (void *) (ip0 + 1);
1223 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1224 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001225 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1226 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227 return p0->flags;
1228 }
1229
1230 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1231
Damjan Marion213b5aa2017-07-13 21:19:27 +02001232 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1233 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234
1235 return p0->flags;
1236}
1237
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301238/**
1239 * @brief returns number of links on which src is reachable.
1240 */
1241always_inline int
1242ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1243{
1244 const load_balance_t *lb0;
1245 index_t lbi;
1246
1247 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1248 vnet_buffer
1249 (b)->sw_if_index[VLIB_RX],
1250 &i->src_address);
1251
1252 lb0 = load_balance_get (lbi);
1253
1254 return (fib_urpf_check_size (lb0->lb_urpf));
1255}
1256
rootc9d1c5b2017-08-15 12:58:31 -04001257always_inline u8
1258ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1259 u32 * udp_offset0)
1260{
1261 u32 proto0;
1262 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1263 if (proto0 != IP_PROTOCOL_UDP)
1264 {
1265 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1266 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1267 }
1268 return proto0;
1269}
1270
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001271/* *INDENT-OFF* */
1272VNET_FEATURE_ARC_INIT (ip6_local) =
1273{
1274 .arc_name = "ip6-local",
1275 .start_nodes = VNET_FEATURES ("ip6-local"),
1276};
1277/* *INDENT-ON* */
1278
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279static uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001280ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1281 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001283 ip6_main_t *im = &ip6_main;
1284 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 u32 *from, *to_next, n_left_from, n_left_to_next;
1287 vlib_node_runtime_t *error_node =
1288 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001289 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 from = vlib_frame_vector_args (frame);
1292 n_left_from = frame->n_vectors;
1293 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001294
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 if (node->flags & VLIB_NODE_FLAG_TRACE)
1296 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1297
1298 while (n_left_from > 0)
1299 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001300 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001301
1302 while (n_left_from >= 4 && n_left_to_next >= 2)
1303 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001304 vlib_buffer_t *p0, *p1;
1305 ip6_header_t *ip0, *ip1;
1306 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 u32 pi0, ip_len0, udp_len0, flags0, next0;
1308 u32 pi1, ip_len1, udp_len1, flags1, next1;
1309 i32 len_diff0, len_diff1;
rootc9d1c5b2017-08-15 12:58:31 -04001310 u8 error0, type0, good_l4_csum0, is_tcp_udp0;
1311 u8 error1, type1, good_l4_csum1, is_tcp_udp1;
Shwethab78292e2016-09-13 11:51:00 +01001312 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001313
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314 pi0 = to_next[0] = from[0];
1315 pi1 = to_next[1] = from[1];
1316 from += 2;
1317 n_left_from -= 2;
1318 to_next += 2;
1319 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001320
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001321 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1322
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 p0 = vlib_get_buffer (vm, pi0);
1324 p1 = vlib_get_buffer (vm, pi1);
1325
1326 ip0 = vlib_buffer_get_current (p0);
1327 ip1 = vlib_buffer_get_current (p1);
1328
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001329 if (head_of_feature_arc == 0)
1330 goto skip_checks;
1331
Damjan Marion072401e2017-07-13 18:53:27 +02001332 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1333 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001334
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1336 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1337
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 flags0 = p0->flags;
1339 flags1 = p1->flags;
1340
rootc9d1c5b2017-08-15 12:58:31 -04001341 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1342 is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
1343
1344 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1345 good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001346 len_diff0 = 0;
1347 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348
rootc9d1c5b2017-08-15 12:58:31 -04001349 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001350 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001351 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001352 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001353 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001354 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001355 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001356 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1357 {
1358 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1359 udp_len0 = clib_net_to_host_u16 (udp0->length);
1360 len_diff0 = ip_len0 - udp_len0;
1361 }
Shwethab78292e2016-09-13 11:51:00 +01001362 }
rootc9d1c5b2017-08-15 12:58:31 -04001363 if (PREDICT_TRUE (is_tcp_udp1))
Shwethab78292e2016-09-13 11:51:00 +01001364 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001365 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001366 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001367 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001368 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001369 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001370 if (is_tcp_udp1 == IP_PROTOCOL_UDP)
1371 {
1372 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1373 udp_len1 = clib_net_to_host_u16 (udp1->length);
1374 len_diff1 = ip_len1 - udp_len1;
1375 }
Shwethab78292e2016-09-13 11:51:00 +01001376 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377
rootc9d1c5b2017-08-15 12:58:31 -04001378 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1379 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1382 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1383
1384 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001385 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001386 && !(flags0 &
1387 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388 {
1389 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001390 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001391 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392 }
1393 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001394 && !good_l4_csum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001395 && !(flags1 &
1396 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 {
1398 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
rootc9d1c5b2017-08-15 12:58:31 -04001399 good_l4_csum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001400 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401 }
1402
1403 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1405 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1406
Dave Barachd7cb1b52016-12-09 09:52:16 -05001407 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1408 IP6_ERROR_UDP_CHECKSUM);
1409 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1410 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001411 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1412 error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001413
1414 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001415 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001416 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1417 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001418 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301420 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001421 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001422 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001423 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1424 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001425 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301427 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001428 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429 }
1430
Florin Corascea194d2017-10-02 00:18:51 -07001431 /* TODO maybe move to lookup? */
1432 vnet_buffer (p0)->ip.fib_index =
1433 vec_elt (im->fib_index_by_sw_if_index,
1434 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1435 vnet_buffer (p0)->ip.fib_index =
1436 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1437 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1438 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1439
1440 vnet_buffer (p1)->ip.fib_index =
1441 vec_elt (im->fib_index_by_sw_if_index,
1442 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
1443 vnet_buffer (p1)->ip.fib_index =
1444 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1445 (u32) ~ 0) ? vnet_buffer (p1)->ip.
1446 fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1447
1448
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001449 skip_checks:
1450
1451 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1452 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1453
Dave Barachd7cb1b52016-12-09 09:52:16 -05001454 next0 =
1455 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1456 next1 =
1457 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458
1459 p0->error = error_node->errors[error0];
1460 p1->error = error_node->errors[error1];
1461
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001462 if (head_of_feature_arc)
1463 {
1464 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1465 vnet_feature_arc_start (arc_index,
1466 vnet_buffer (p0)->sw_if_index
1467 [VLIB_RX], &next0, p0);
1468 if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1469 vnet_feature_arc_start (arc_index,
1470 vnet_buffer (p1)->sw_if_index
1471 [VLIB_RX], &next1, p1);
1472 }
1473
Ed Warnickecb9cada2015-12-08 15:45:58 -07001474 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1475 to_next, n_left_to_next,
1476 pi0, pi1, next0, next1);
1477 }
1478
1479 while (n_left_from > 0 && n_left_to_next > 0)
1480 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001481 vlib_buffer_t *p0;
1482 ip6_header_t *ip0;
1483 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001484 u32 pi0, ip_len0, udp_len0, flags0, next0;
1485 i32 len_diff0;
rootc9d1c5b2017-08-15 12:58:31 -04001486 u8 error0, type0, good_l4_csum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001487 u32 udp_offset0;
rootc9d1c5b2017-08-15 12:58:31 -04001488 u8 is_tcp_udp0;
Dave Barach75fc8542016-10-11 16:16:02 -04001489
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490 pi0 = to_next[0] = from[0];
1491 from += 1;
1492 n_left_from -= 1;
1493 to_next += 1;
1494 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001495
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001496 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1497
Ed Warnickecb9cada2015-12-08 15:45:58 -07001498 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001499 ip0 = vlib_buffer_get_current (p0);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001500
1501 if (head_of_feature_arc == 0)
1502 goto skip_check;
1503
Damjan Marion072401e2017-07-13 18:53:27 +02001504 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001505
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001507 flags0 = p0->flags;
rootc9d1c5b2017-08-15 12:58:31 -04001508 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1509 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001510
Shwethab78292e2016-09-13 11:51:00 +01001511 len_diff0 = 0;
rootc9d1c5b2017-08-15 12:58:31 -04001512 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001513 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001514 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
rootc9d1c5b2017-08-15 12:58:31 -04001515 /* Don't verify UDP checksum for packets with explicit zero
1516 * checksum. */
1517 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001518 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001519 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001520 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1521 {
1522 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1523 udp_len0 = clib_net_to_host_u16 (udp0->length);
1524 len_diff0 = ip_len0 - udp_len0;
1525 }
Shwethab78292e2016-09-13 11:51:00 +01001526 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001527
rootc9d1c5b2017-08-15 12:58:31 -04001528 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1530
1531 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001532 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001533 && !(flags0 &
1534 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001535 {
1536 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001537 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001538 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001539 }
1540
1541 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1543
Dave Barachd7cb1b52016-12-09 09:52:16 -05001544 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1545 IP6_ERROR_UDP_CHECKSUM);
1546 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1547 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001548 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549
rootc9d1c5b2017-08-15 12:58:31 -04001550 /* If this is a neighbor solicitation (ICMP), skip src RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001551 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1552 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001553 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001554 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301555 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001556 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557 }
1558
Florin Corascea194d2017-10-02 00:18:51 -07001559 vnet_buffer (p0)->ip.fib_index =
1560 vec_elt (im->fib_index_by_sw_if_index,
1561 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1562 vnet_buffer (p0)->ip.fib_index =
1563 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1564 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1565 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1566
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001567 skip_check:
1568
1569 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001570 next0 =
1571 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001572 p0->error = error_node->errors[error0];
1573
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001574 if (head_of_feature_arc)
1575 {
1576 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1577 vnet_feature_arc_start (arc_index,
1578 vnet_buffer (p0)->sw_if_index
1579 [VLIB_RX], &next0, p0);
1580 }
1581
Ed Warnickecb9cada2015-12-08 15:45:58 -07001582 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1583 to_next, n_left_to_next,
1584 pi0, next0);
1585 }
Dave Barach75fc8542016-10-11 16:16:02 -04001586
Ed Warnickecb9cada2015-12-08 15:45:58 -07001587 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1588 }
1589
1590 return frame->n_vectors;
1591}
1592
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001593static uword
1594ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1595{
1596 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1597}
1598
Dave Barachd7cb1b52016-12-09 09:52:16 -05001599/* *INDENT-OFF* */
1600VLIB_REGISTER_NODE (ip6_local_node, static) =
1601{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602 .function = ip6_local,
1603 .name = "ip6-local",
1604 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001606 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001607 .next_nodes =
1608 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001609 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1610 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1612 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1613 },
1614};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001615/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001616
Dave Barachd7cb1b52016-12-09 09:52:16 -05001617VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001618
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001619
1620static uword
1621ip6_local_end_of_arc (vlib_main_t * vm,
1622 vlib_node_runtime_t * node, vlib_frame_t * frame)
1623{
1624 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1625}
1626
1627/* *INDENT-OFF* */
1628VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
1629 .function = ip6_local_end_of_arc,
1630 .name = "ip6-local-end-of-arc",
1631 .vector_size = sizeof (u32),
1632
1633 .format_trace = format_ip6_forward_next_trace,
1634 .sibling_of = "ip6-local",
1635};
1636
1637VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
1638
1639VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1640 .arc_name = "ip6-local",
1641 .node_name = "ip6-local-end-of-arc",
1642 .runs_before = 0, /* not before any other features */
1643};
1644/* *INDENT-ON* */
1645
Dave Barachd7cb1b52016-12-09 09:52:16 -05001646void
1647ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001648{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001649 vlib_main_t *vm = vlib_get_main ();
1650 ip6_main_t *im = &ip6_main;
1651 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001652
1653 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001654 lm->local_next_by_ip_protocol[protocol] =
1655 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001656}
1657
Dave Barachd7cb1b52016-12-09 09:52:16 -05001658typedef enum
1659{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001660 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001661 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001662 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1663} ip6_discover_neighbor_next_t;
1664
Dave Barachd7cb1b52016-12-09 09:52:16 -05001665typedef enum
1666{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1668 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001669 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001670} ip6_discover_neighbor_error_t;
1671
1672static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001673ip6_discover_neighbor_inline (vlib_main_t * vm,
1674 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001675 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001676{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001677 vnet_main_t *vnm = vnet_get_main ();
1678 ip6_main_t *im = &ip6_main;
1679 ip_lookup_main_t *lm = &im->lookup_main;
1680 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001681 uword n_left_from, n_left_to_next_drop;
1682 static f64 time_last_seed_change = -1e100;
1683 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001684 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685 f64 time_now;
1686 int bogus_length;
1687
1688 if (node->flags & VLIB_NODE_FLAG_TRACE)
1689 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1690
1691 time_now = vlib_time_now (vm);
1692 if (time_now - time_last_seed_change > 1e-3)
1693 {
1694 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001695 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1696 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001697 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1698 hash_seeds[i] = r[i];
1699
1700 /* Mark all hash keys as been not-seen before. */
1701 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1702 hash_bitmap[i] = 0;
1703
1704 time_last_seed_change = time_now;
1705 }
1706
1707 from = vlib_frame_vector_args (frame);
1708 n_left_from = frame->n_vectors;
1709
1710 while (n_left_from > 0)
1711 {
1712 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1713 to_next_drop, n_left_to_next_drop);
1714
1715 while (n_left_from > 0 && n_left_to_next_drop > 0)
1716 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001717 vlib_buffer_t *p0;
1718 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001719 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1720 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001721 ip_adjacency_t *adj0;
1722 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001723 u32 next0;
1724
1725 pi0 = from[0];
1726
1727 p0 = vlib_get_buffer (vm, pi0);
1728
1729 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1730
1731 ip0 = vlib_buffer_get_current (p0);
1732
Neale Ranns107e7d42017-04-11 09:55:19 -07001733 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001734
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001735 if (!is_glean)
1736 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001737 ip0->dst_address.as_u64[0] =
1738 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1739 ip0->dst_address.as_u64[1] =
1740 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001741 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001742
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743 a0 = hash_seeds[0];
1744 b0 = hash_seeds[1];
1745 c0 = hash_seeds[2];
1746
1747 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1748 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1749
1750 a0 ^= sw_if_index0;
1751 b0 ^= ip0->dst_address.as_u32[0];
1752 c0 ^= ip0->dst_address.as_u32[1];
1753
1754 hash_v3_mix32 (a0, b0, c0);
1755
1756 b0 ^= ip0->dst_address.as_u32[2];
1757 c0 ^= ip0->dst_address.as_u32[3];
1758
1759 hash_v3_finalize32 (a0, b0, c0);
1760
1761 c0 &= BITS (hash_bitmap) - 1;
1762 c0 = c0 / BITS (uword);
1763 m0 = (uword) 1 << (c0 % BITS (uword));
1764
1765 bm0 = hash_bitmap[c0];
1766 drop0 = (bm0 & m0) != 0;
1767
1768 /* Mark it as seen. */
1769 hash_bitmap[c0] = bm0 | m0;
1770
1771 from += 1;
1772 n_left_from -= 1;
1773 to_next_drop[0] = pi0;
1774 to_next_drop += 1;
1775 n_left_to_next_drop -= 1;
1776
Dave Barachd7cb1b52016-12-09 09:52:16 -05001777 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001778
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 /* If the interface is link-down, drop the pkt */
1780 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1781 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782
Dave Barach75fc8542016-10-11 16:16:02 -04001783 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001784 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1785 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 if (drop0)
1787 continue;
1788
Neale Rannsb80c5362016-10-08 13:03:40 +01001789 /*
1790 * the adj has been updated to a rewrite but the node the DPO that got
1791 * us here hasn't - yet. no big deal. we'll drop while we wait.
1792 */
1793 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1794 continue;
1795
Ed Warnickecb9cada2015-12-08 15:45:58 -07001796 {
1797 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001798 icmp6_neighbor_solicitation_header_t *h0;
1799 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001800
Dave Barach75fc8542016-10-11 16:16:02 -04001801 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001802 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001803
Dave Barach75fc8542016-10-11 16:16:02 -04001804 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001805 * Build ethernet header.
1806 * Choose source address based on destination lookup
1807 * adjacency.
1808 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001809 if (ip6_src_address_for_packet (lm,
1810 sw_if_index0,
1811 &h0->ip.src_address))
1812 {
1813 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001814 p0->error =
1815 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1816 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001817 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001818 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001819
Dave Barach75fc8542016-10-11 16:16:02 -04001820 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001821 * Destination address is a solicited node multicast address.
1822 * We need to fill in
1823 * the low 24 bits with low 24 bits of target's address.
1824 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001825 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1826 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1827 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1828
1829 h0->neighbor.target_address = ip0->dst_address;
1830
Dave Barach75fc8542016-10-11 16:16:02 -04001831 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001832 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001833
Dave Barachd7cb1b52016-12-09 09:52:16 -05001834 /* $$$$ appears we need this; why is the checksum non-zero? */
1835 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001836 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1838 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001839
Dave Barachd7cb1b52016-12-09 09:52:16 -05001840 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841
1842 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1843 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001844 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001845 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001846
1847 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001848 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001849 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1850
John Lod1f5d042016-04-12 18:20:39 -04001851 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852
1853 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1854 }
1855 }
1856
Dave Barach75fc8542016-10-11 16:16:02 -04001857 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001858 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859 }
1860
1861 return frame->n_vectors;
1862}
1863
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001864static uword
1865ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001866 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001867{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001868 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001869}
1870
1871static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001872ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001873{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001874 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001875}
1876
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001878 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001879 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001880 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1881 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882};
1883
Dave Barachd7cb1b52016-12-09 09:52:16 -05001884/* *INDENT-OFF* */
1885VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1886{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887 .function = ip6_discover_neighbor,
1888 .name = "ip6-discover-neighbor",
1889 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001891 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1892 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001894 .next_nodes =
1895 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001897 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001898 },
1899};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001901
Dave Barachd7cb1b52016-12-09 09:52:16 -05001902/* *INDENT-OFF* */
1903VLIB_REGISTER_NODE (ip6_glean_node) =
1904{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001905 .function = ip6_glean,
1906 .name = "ip6-glean",
1907 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001908 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001909 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1910 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001911 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001912 .next_nodes =
1913 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001914 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1915 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1916 },
1917};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001918/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001919
Ed Warnickecb9cada2015-12-08 15:45:58 -07001920clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001921ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1922{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001923 vnet_main_t *vnm = vnet_get_main ();
1924 ip6_main_t *im = &ip6_main;
1925 icmp6_neighbor_solicitation_header_t *h;
1926 ip6_address_t *src;
1927 ip_interface_address_t *ia;
1928 ip_adjacency_t *adj;
1929 vnet_hw_interface_t *hi;
1930 vnet_sw_interface_t *si;
1931 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001932 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001933 u32 bi = 0;
1934 int bogus_length;
1935
1936 si = vnet_get_sw_interface (vnm, sw_if_index);
1937
1938 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1939 {
1940 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001941 format_ip6_address, dst,
1942 format_vnet_sw_if_index_name, vnm,
1943 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944 }
1945
Dave Barachd7cb1b52016-12-09 09:52:16 -05001946 src =
1947 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1948 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001949 {
1950 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001951 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001952 (0, "no matching interface address for destination %U (interface %U)",
1953 format_ip6_address, dst,
1954 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001955 }
1956
Dave Barachd7cb1b52016-12-09 09:52:16 -05001957 h =
1958 vlib_packet_template_get_packet (vm,
1959 &im->discover_neighbor_packet_template,
1960 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961
1962 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1963
1964 /* Destination address is a solicited node multicast address. We need to fill in
1965 the low 24 bits with low 24 bits of target's address. */
1966 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1967 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1968 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1969
1970 h->ip.src_address = src[0];
1971 h->neighbor.target_address = dst[0];
1972
Pavel Kotucek57808982017-08-02 08:20:19 +02001973 if (PREDICT_FALSE (!hi->hw_address))
1974 {
1975 return clib_error_return (0, "%U: interface %U do not support ip probe",
1976 format_ip6_address, dst,
1977 format_vnet_sw_if_index_name, vnm,
1978 sw_if_index);
1979 }
1980
Dave Barachd7cb1b52016-12-09 09:52:16 -05001981 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1982 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983
Dave Barach75fc8542016-10-11 16:16:02 -04001984 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001985 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001986 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987
1988 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001989 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1990 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001991
1992 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07001993 ip46_address_t nh = {
1994 .ip6 = *dst,
1995 };
1996
1997 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
1998 VNET_LINK_IP6, &nh, sw_if_index);
1999 adj = adj_get (ai);
2000
Dave Barach59b25652017-09-10 15:04:27 -04002001 /* Peer has been previously resolved, retrieve glean adj instead */
2002 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2003 {
2004 adj_unlock (ai);
2005 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6, sw_if_index, &nh);
2006 adj = adj_get (ai);
2007 }
2008
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2010 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2011
2012 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002013 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2014 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002015 to_next[0] = bi;
2016 f->n_vectors = 1;
2017 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2018 }
2019
Neale Ranns7a272742017-05-30 02:08:14 -07002020 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002021 return /* no error */ 0;
2022}
2023
Dave Barachd7cb1b52016-12-09 09:52:16 -05002024typedef enum
2025{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002026 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002027 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028} ip6_rewrite_next_t;
2029
2030always_inline uword
2031ip6_rewrite_inline (vlib_main_t * vm,
2032 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002033 vlib_frame_t * frame,
2034 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002035{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 ip_lookup_main_t *lm = &ip6_main.lookup_main;
2037 u32 *from = vlib_frame_vector_args (frame);
2038 u32 n_left_from, n_left_to_next, *to_next, next_index;
2039 vlib_node_runtime_t *error_node =
2040 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041
2042 n_left_from = frame->n_vectors;
2043 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002044 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002045
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046 while (n_left_from > 0)
2047 {
2048 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2049
2050 while (n_left_from >= 4 && n_left_to_next >= 2)
2051 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002052 ip_adjacency_t *adj0, *adj1;
2053 vlib_buffer_t *p0, *p1;
2054 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055 u32 pi0, rw_len0, next0, error0, adj_index0;
2056 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002057 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04002058
Ed Warnickecb9cada2015-12-08 15:45:58 -07002059 /* Prefetch next iteration. */
2060 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002061 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002062
2063 p2 = vlib_get_buffer (vm, from[2]);
2064 p3 = vlib_get_buffer (vm, from[3]);
2065
2066 vlib_prefetch_buffer_header (p2, LOAD);
2067 vlib_prefetch_buffer_header (p3, LOAD);
2068
2069 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2070 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2071
2072 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2073 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2074 }
2075
2076 pi0 = to_next[0] = from[0];
2077 pi1 = to_next[1] = from[1];
2078
2079 from += 2;
2080 n_left_from -= 2;
2081 to_next += 2;
2082 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002083
Ed Warnickecb9cada2015-12-08 15:45:58 -07002084 p0 = vlib_get_buffer (vm, pi0);
2085 p1 = vlib_get_buffer (vm, pi1);
2086
Neale Rannsf06aea52016-11-29 06:51:37 -08002087 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2088 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002089
Ed Warnickecb9cada2015-12-08 15:45:58 -07002090 ip0 = vlib_buffer_get_current (p0);
2091 ip1 = vlib_buffer_get_current (p1);
2092
2093 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002094 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002095
Damjan Marion213b5aa2017-07-13 21:19:27 +02002096 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002097 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002098 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099
2100 /* Input node should have reject packets with hop limit 0. */
2101 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002102
2103 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104
2105 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106
Dave Barachd7cb1b52016-12-09 09:52:16 -05002107 /*
2108 * If the hop count drops below 1 when forwarding, generate
2109 * an ICMP response.
2110 */
2111 if (PREDICT_FALSE (hop_limit0 <= 0))
2112 {
2113 error0 = IP6_ERROR_TIME_EXPIRED;
2114 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2115 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2116 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2117 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2118 0);
2119 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002120 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002121 else
2122 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002123 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002124 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002125 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002126 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002127 i32 hop_limit1 = ip1->hop_limit;
2128
2129 /* Input node should have reject packets with hop limit 0. */
2130 ASSERT (ip1->hop_limit > 0);
2131
2132 hop_limit1 -= 1;
2133
2134 ip1->hop_limit = hop_limit1;
2135
Dave Barachd7cb1b52016-12-09 09:52:16 -05002136 /*
2137 * If the hop count drops below 1 when forwarding, generate
2138 * an ICMP response.
2139 */
2140 if (PREDICT_FALSE (hop_limit1 <= 0))
2141 {
2142 error1 = IP6_ERROR_TIME_EXPIRED;
2143 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2144 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2145 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2146 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2147 0);
2148 }
2149 }
2150 else
2151 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002152 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002153 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002154 adj0 = adj_get (adj_index0);
2155 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002156
Ed Warnickecb9cada2015-12-08 15:45:58 -07002157 rw_len0 = adj0[0].rewrite_header.data_bytes;
2158 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002159 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2160 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161
Neale Ranns9c6a6132017-02-21 05:33:14 -08002162 if (do_counters)
2163 {
2164 vlib_increment_combined_counter
2165 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002166 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002167 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2168 vlib_increment_combined_counter
2169 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002170 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002171 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2172 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002173
2174 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002175 error0 =
2176 (vlib_buffer_length_in_chain (vm, p0) >
2177 adj0[0].
2178 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2179 error0);
2180 error1 =
2181 (vlib_buffer_length_in_chain (vm, p1) >
2182 adj1[0].
2183 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2184 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002185
Dave Barachd7cb1b52016-12-09 09:52:16 -05002186 /* Don't adjust the buffer for hop count issue; icmp-error node
2187 * wants to see the IP headerr */
2188 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2189 {
2190 p0->current_data -= rw_len0;
2191 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192
Dave Barachd7cb1b52016-12-09 09:52:16 -05002193 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2194 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2195 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002196
Neale Rannsb069a692017-03-15 12:34:25 -04002197 if (PREDICT_FALSE
2198 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2199 vnet_feature_arc_start (lm->output_feature_arc_index,
2200 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002201 }
2202 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2203 {
2204 p1->current_data -= rw_len1;
2205 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002206
Dave Barachd7cb1b52016-12-09 09:52:16 -05002207 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2208 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2209 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002210
Neale Rannsb069a692017-03-15 12:34:25 -04002211 if (PREDICT_FALSE
2212 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2213 vnet_feature_arc_start (lm->output_feature_arc_index,
2214 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002215 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002216
2217 /* Guess we are only writing on simple Ethernet header. */
2218 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002219 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002220
Neale Ranns5e575b12016-10-03 09:40:25 +01002221 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002222 {
2223 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2224 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2225 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002226 if (is_mcast)
2227 {
2228 /*
2229 * copy bytes from the IP address into the MAC rewrite
2230 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002231 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2232 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002233 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002234
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2236 to_next, n_left_to_next,
2237 pi0, pi1, next0, next1);
2238 }
2239
2240 while (n_left_from > 0 && n_left_to_next > 0)
2241 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002242 ip_adjacency_t *adj0;
2243 vlib_buffer_t *p0;
2244 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002245 u32 pi0, rw_len0;
2246 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002248
Ed Warnickecb9cada2015-12-08 15:45:58 -07002249 pi0 = to_next[0] = from[0];
2250
2251 p0 = vlib_get_buffer (vm, pi0);
2252
Neale Rannsf06aea52016-11-29 06:51:37 -08002253 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254
Neale Ranns107e7d42017-04-11 09:55:19 -07002255 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002256
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257 ip0 = vlib_buffer_get_current (p0);
2258
2259 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002260 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261
2262 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002263 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002264 {
2265 i32 hop_limit0 = ip0->hop_limit;
2266
2267 ASSERT (ip0->hop_limit > 0);
2268
2269 hop_limit0 -= 1;
2270
2271 ip0->hop_limit = hop_limit0;
2272
Dave Barachd7cb1b52016-12-09 09:52:16 -05002273 if (PREDICT_FALSE (hop_limit0 <= 0))
2274 {
2275 /*
2276 * If the hop count drops below 1 when forwarding, generate
2277 * an ICMP response.
2278 */
2279 error0 = IP6_ERROR_TIME_EXPIRED;
2280 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2281 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2282 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2283 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2284 0);
2285 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002286 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002287 else
2288 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002289 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002290 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002291
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 /* Guess we are only writing on simple Ethernet header. */
2293 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002294
Ed Warnickecb9cada2015-12-08 15:45:58 -07002295 /* Update packet buffer attributes/set output interface. */
2296 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002297 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002298
Neale Ranns9c6a6132017-02-21 05:33:14 -08002299 if (do_counters)
2300 {
2301 vlib_increment_combined_counter
2302 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002303 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002304 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2305 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306
2307 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002308 error0 =
2309 (vlib_buffer_length_in_chain (vm, p0) >
2310 adj0[0].
2311 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2312 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
Dave Barachd7cb1b52016-12-09 09:52:16 -05002314 /* Don't adjust the buffer for hop count issue; icmp-error node
2315 * wants to see the IP headerr */
2316 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2317 {
Chris Luke816f3e12016-06-14 16:24:47 -04002318 p0->current_data -= rw_len0;
2319 p0->current_length += rw_len0;
2320
Dave Barachd7cb1b52016-12-09 09:52:16 -05002321 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002322
Dave Barachd7cb1b52016-12-09 09:52:16 -05002323 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2324 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002325
Neale Rannsb069a692017-03-15 12:34:25 -04002326 if (PREDICT_FALSE
2327 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2328 vnet_feature_arc_start (lm->output_feature_arc_index,
2329 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002331
Neale Ranns5e575b12016-10-03 09:40:25 +01002332 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002333 {
2334 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2335 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002336 if (is_mcast)
2337 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002338 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002339 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002340
Ed Warnickecb9cada2015-12-08 15:45:58 -07002341 p0->error = error_node->errors[error0];
2342
2343 from += 1;
2344 n_left_from -= 1;
2345 to_next += 1;
2346 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002347
Ed Warnickecb9cada2015-12-08 15:45:58 -07002348 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2349 to_next, n_left_to_next,
2350 pi0, next0);
2351 }
2352
2353 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2354 }
2355
2356 /* Need to do trace after rewrites to pick up new packet data. */
2357 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002358 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002359
2360 return frame->n_vectors;
2361}
2362
2363static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002364ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002365 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002366{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002367 if (adj_are_counters_enabled ())
2368 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2369 else
2370 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002371}
2372
2373static uword
2374ip6_rewrite_mcast (vlib_main_t * vm,
2375 vlib_node_runtime_t * node, vlib_frame_t * frame)
2376{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002377 if (adj_are_counters_enabled ())
2378 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2379 else
2380 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381}
2382
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002383static uword
2384ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002385 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002386{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002387 if (adj_are_counters_enabled ())
2388 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2389 else
2390 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002391}
2392
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002393static uword
2394ip6_mcast_midchain (vlib_main_t * vm,
2395 vlib_node_runtime_t * node, vlib_frame_t * frame)
2396{
2397 if (adj_are_counters_enabled ())
2398 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2399 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002400 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002401}
2402
Dave Barachd7cb1b52016-12-09 09:52:16 -05002403/* *INDENT-OFF* */
2404VLIB_REGISTER_NODE (ip6_midchain_node) =
2405{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002406 .function = ip6_midchain,
2407 .name = "ip6-midchain",
2408 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002409 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002410 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002411 };
2412/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002413
Dave Barachd7cb1b52016-12-09 09:52:16 -05002414VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002415
Dave Barachd7cb1b52016-12-09 09:52:16 -05002416/* *INDENT-OFF* */
2417VLIB_REGISTER_NODE (ip6_rewrite_node) =
2418{
Neale Rannsf06aea52016-11-29 06:51:37 -08002419 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002420 .name = "ip6-rewrite",
2421 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002422 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002423 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002424 .next_nodes =
2425 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002426 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002427 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002428 },
2429};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002430/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002431
Neale Rannsf06aea52016-11-29 06:51:37 -08002432VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002433
Neale Ranns32e1c012016-11-22 17:07:28 +00002434/* *INDENT-OFF* */
2435VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2436{
2437 .function = ip6_rewrite_mcast,
2438 .name = "ip6-rewrite-mcast",
2439 .vector_size = sizeof (u32),
2440 .format_trace = format_ip6_rewrite_trace,
2441 .sibling_of = "ip6-rewrite",
2442};
2443/* *INDENT-ON* */
2444
2445VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2446
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002447/* *INDENT-OFF* */
2448VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2449{
2450 .function = ip6_mcast_midchain,
2451 .name = "ip6-mcast-midchain",
2452 .vector_size = sizeof (u32),
2453 .format_trace = format_ip6_rewrite_trace,
2454 .sibling_of = "ip6-rewrite",
2455};
2456/* *INDENT-ON* */
2457
2458VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2459
Ole Troan944f5482016-05-24 11:56:58 +02002460/*
2461 * Hop-by-Hop handling
2462 */
Ole Troan944f5482016-05-24 11:56:58 +02002463ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2464
2465#define foreach_ip6_hop_by_hop_error \
2466_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2467_(FORMAT, "incorrectly formatted hop-by-hop options") \
2468_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2469
Neale Ranns32e1c012016-11-22 17:07:28 +00002470/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002471typedef enum
2472{
Ole Troan944f5482016-05-24 11:56:58 +02002473#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2474 foreach_ip6_hop_by_hop_error
2475#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002476 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002477} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002478/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002479
2480/*
2481 * Primary h-b-h handler trace support
2482 * We work pretty hard on the problem for obvious reasons
2483 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002484typedef struct
2485{
Ole Troan944f5482016-05-24 11:56:58 +02002486 u32 next_index;
2487 u32 trace_len;
2488 u8 option_data[256];
2489} ip6_hop_by_hop_trace_t;
2490
2491vlib_node_registration_t ip6_hop_by_hop_node;
2492
Dave Barachd7cb1b52016-12-09 09:52:16 -05002493static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002494#define _(sym,string) string,
2495 foreach_ip6_hop_by_hop_error
2496#undef _
2497};
2498
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302499u8 *
2500format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2501{
2502 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2503 int total_len = va_arg (*args, int);
2504 ip6_hop_by_hop_option_t *opt0, *limit0;
2505 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2506 u8 type0;
2507
2508 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2509 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2510
2511 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2512 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2513
2514 while (opt0 < limit0)
2515 {
2516 type0 = opt0->type;
2517 switch (type0)
2518 {
2519 case 0: /* Pad, just stop */
2520 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2521 break;
2522
2523 default:
2524 if (hm->trace[type0])
2525 {
2526 s = (*hm->trace[type0]) (s, opt0);
2527 }
2528 else
2529 {
2530 s =
2531 format (s, "\n unrecognized option %d length %d", type0,
2532 opt0->length);
2533 }
2534 opt0 =
2535 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2536 sizeof (ip6_hop_by_hop_option_t));
2537 break;
2538 }
2539 }
2540 return s;
2541}
2542
Ole Troan944f5482016-05-24 11:56:58 +02002543static u8 *
2544format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2545{
2546 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2547 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002548 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002549 ip6_hop_by_hop_header_t *hbh0;
2550 ip6_hop_by_hop_option_t *opt0, *limit0;
2551 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2552
2553 u8 type0;
2554
Dave Barachd7cb1b52016-12-09 09:52:16 -05002555 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002556
2557 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002558 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002559
Dave Barachd7cb1b52016-12-09 09:52:16 -05002560 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2561 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002562
Dave Barachd7cb1b52016-12-09 09:52:16 -05002563 while (opt0 < limit0)
2564 {
2565 type0 = opt0->type;
2566 switch (type0)
2567 {
2568 case 0: /* Pad, just stop */
2569 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2570 break;
Ole Troan944f5482016-05-24 11:56:58 +02002571
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 default:
2573 if (hm->trace[type0])
2574 {
2575 s = (*hm->trace[type0]) (s, opt0);
2576 }
2577 else
2578 {
2579 s =
2580 format (s, "\n unrecognized option %d length %d", type0,
2581 opt0->length);
2582 }
2583 opt0 =
2584 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2585 sizeof (ip6_hop_by_hop_option_t));
2586 break;
2587 }
Ole Troan944f5482016-05-24 11:56:58 +02002588 }
Ole Troan944f5482016-05-24 11:56:58 +02002589 return s;
2590}
2591
Dave Barachd7cb1b52016-12-09 09:52:16 -05002592always_inline u8
2593ip6_scan_hbh_options (vlib_buffer_t * b0,
2594 ip6_header_t * ip0,
2595 ip6_hop_by_hop_header_t * hbh0,
2596 ip6_hop_by_hop_option_t * opt0,
2597 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002598{
2599 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2600 u8 type0;
2601 u8 error0 = 0;
2602
2603 while (opt0 < limit0)
2604 {
2605 type0 = opt0->type;
2606 switch (type0)
2607 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002608 case 0: /* Pad1 */
2609 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002610 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002611 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002612 break;
2613 default:
2614 if (hm->options[type0])
2615 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002616 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2617 {
Shwethaa91cbe62016-08-08 15:51:04 +01002618 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002619 return (error0);
2620 }
Shwethaa91cbe62016-08-08 15:51:04 +01002621 }
2622 else
2623 {
2624 /* Unrecognized mandatory option, check the two high order bits */
2625 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2626 {
2627 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2628 break;
2629 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2630 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2631 *next0 = IP_LOOKUP_NEXT_DROP;
2632 break;
2633 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2634 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2635 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002636 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2637 ICMP6_parameter_problem_unrecognized_option,
2638 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002639 break;
2640 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2641 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002642 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002643 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002644 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2645 icmp6_error_set_vnet_buffer (b0,
2646 ICMP6_parameter_problem,
2647 ICMP6_parameter_problem_unrecognized_option,
2648 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002649 }
2650 else
2651 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002652 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002653 }
2654 break;
2655 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002656 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002657 }
2658 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002659 opt0 =
2660 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2661 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002662 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002663 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002664}
2665
Ole Troan944f5482016-05-24 11:56:58 +02002666/*
2667 * Process the Hop-by-Hop Options header
2668 */
2669static uword
2670ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002671 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002672{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002673 vlib_node_runtime_t *error_node =
2674 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002675 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2676 u32 n_left_from, *from, *to_next;
2677 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002678
2679 from = vlib_frame_vector_args (frame);
2680 n_left_from = frame->n_vectors;
2681 next_index = node->cached_next_index;
2682
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683 while (n_left_from > 0)
2684 {
2685 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002686
Dave Barachd7cb1b52016-12-09 09:52:16 -05002687 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002688
Dave Barachd7cb1b52016-12-09 09:52:16 -05002689 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002690 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002691 u32 bi0, bi1;
2692 vlib_buffer_t *b0, *b1;
2693 u32 next0, next1;
2694 ip6_header_t *ip0, *ip1;
2695 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2696 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2697 u8 error0 = 0, error1 = 0;
2698
2699 /* Prefetch next iteration. */
2700 {
2701 vlib_buffer_t *p2, *p3;
2702
2703 p2 = vlib_get_buffer (vm, from[2]);
2704 p3 = vlib_get_buffer (vm, from[3]);
2705
2706 vlib_prefetch_buffer_header (p2, LOAD);
2707 vlib_prefetch_buffer_header (p3, LOAD);
2708
2709 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2710 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002711 }
2712
Dave Barachd7cb1b52016-12-09 09:52:16 -05002713 /* Speculatively enqueue b0, b1 to the current next frame */
2714 to_next[0] = bi0 = from[0];
2715 to_next[1] = bi1 = from[1];
2716 from += 2;
2717 to_next += 2;
2718 n_left_from -= 2;
2719 n_left_to_next -= 2;
2720
2721 b0 = vlib_get_buffer (vm, bi0);
2722 b1 = vlib_get_buffer (vm, bi1);
2723
2724 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2725 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002726 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002727 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002728 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002729
2730 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2731 next0 = adj0->lookup_next_index;
2732 next1 = adj1->lookup_next_index;
2733
2734 ip0 = vlib_buffer_get_current (b0);
2735 ip1 = vlib_buffer_get_current (b1);
2736 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2737 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2738 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2739 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2740 limit0 =
2741 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2742 ((hbh0->length + 1) << 3));
2743 limit1 =
2744 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2745 ((hbh1->length + 1) << 3));
2746
2747 /*
2748 * Basic validity checks
2749 */
2750 if ((hbh0->length + 1) << 3 >
2751 clib_net_to_host_u16 (ip0->payload_length))
2752 {
2753 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2754 next0 = IP_LOOKUP_NEXT_DROP;
2755 goto outdual;
2756 }
2757 /* Scan the set of h-b-h options, process ones that we understand */
2758 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2759
2760 if ((hbh1->length + 1) << 3 >
2761 clib_net_to_host_u16 (ip1->payload_length))
2762 {
2763 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2764 next1 = IP_LOOKUP_NEXT_DROP;
2765 goto outdual;
2766 }
2767 /* Scan the set of h-b-h options, process ones that we understand */
2768 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2769
2770 outdual:
2771 /* Has the classifier flagged this buffer for special treatment? */
2772 if (PREDICT_FALSE
2773 ((error0 == 0)
2774 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2775 next0 = hm->next_override;
2776
2777 /* Has the classifier flagged this buffer for special treatment? */
2778 if (PREDICT_FALSE
2779 ((error1 == 0)
2780 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2781 next1 = hm->next_override;
2782
2783 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2784 {
2785 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2786 {
2787 ip6_hop_by_hop_trace_t *t =
2788 vlib_add_trace (vm, node, b0, sizeof (*t));
2789 u32 trace_len = (hbh0->length + 1) << 3;
2790 t->next_index = next0;
2791 /* Capture the h-b-h option verbatim */
2792 trace_len =
2793 trace_len <
2794 ARRAY_LEN (t->option_data) ? trace_len :
2795 ARRAY_LEN (t->option_data);
2796 t->trace_len = trace_len;
2797 clib_memcpy (t->option_data, hbh0, trace_len);
2798 }
2799 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2800 {
2801 ip6_hop_by_hop_trace_t *t =
2802 vlib_add_trace (vm, node, b1, sizeof (*t));
2803 u32 trace_len = (hbh1->length + 1) << 3;
2804 t->next_index = next1;
2805 /* Capture the h-b-h option verbatim */
2806 trace_len =
2807 trace_len <
2808 ARRAY_LEN (t->option_data) ? trace_len :
2809 ARRAY_LEN (t->option_data);
2810 t->trace_len = trace_len;
2811 clib_memcpy (t->option_data, hbh1, trace_len);
2812 }
2813
2814 }
2815
2816 b0->error = error_node->errors[error0];
2817 b1->error = error_node->errors[error1];
2818
2819 /* verify speculative enqueue, maybe switch current next frame */
2820 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2821 n_left_to_next, bi0, bi1, next0,
2822 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002823 }
2824
Dave Barachd7cb1b52016-12-09 09:52:16 -05002825 while (n_left_from > 0 && n_left_to_next > 0)
2826 {
2827 u32 bi0;
2828 vlib_buffer_t *b0;
2829 u32 next0;
2830 ip6_header_t *ip0;
2831 ip6_hop_by_hop_header_t *hbh0;
2832 ip6_hop_by_hop_option_t *opt0, *limit0;
2833 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002834
Dave Barachd7cb1b52016-12-09 09:52:16 -05002835 /* Speculatively enqueue b0 to the current next frame */
2836 bi0 = from[0];
2837 to_next[0] = bi0;
2838 from += 1;
2839 to_next += 1;
2840 n_left_from -= 1;
2841 n_left_to_next -= 1;
2842
2843 b0 = vlib_get_buffer (vm, bi0);
2844 /*
2845 * Default use the next_index from the adjacency.
2846 * A HBH option rarely redirects to a different node
2847 */
2848 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002849 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002850 next0 = adj0->lookup_next_index;
2851
2852 ip0 = vlib_buffer_get_current (b0);
2853 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2854 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2855 limit0 =
2856 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2857 ((hbh0->length + 1) << 3));
2858
2859 /*
2860 * Basic validity checks
2861 */
2862 if ((hbh0->length + 1) << 3 >
2863 clib_net_to_host_u16 (ip0->payload_length))
2864 {
2865 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2866 next0 = IP_LOOKUP_NEXT_DROP;
2867 goto out0;
2868 }
2869
2870 /* Scan the set of h-b-h options, process ones that we understand */
2871 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2872
2873 out0:
2874 /* Has the classifier flagged this buffer for special treatment? */
2875 if (PREDICT_FALSE
2876 ((error0 == 0)
2877 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2878 next0 = hm->next_override;
2879
2880 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2881 {
2882 ip6_hop_by_hop_trace_t *t =
2883 vlib_add_trace (vm, node, b0, sizeof (*t));
2884 u32 trace_len = (hbh0->length + 1) << 3;
2885 t->next_index = next0;
2886 /* Capture the h-b-h option verbatim */
2887 trace_len =
2888 trace_len <
2889 ARRAY_LEN (t->option_data) ? trace_len :
2890 ARRAY_LEN (t->option_data);
2891 t->trace_len = trace_len;
2892 clib_memcpy (t->option_data, hbh0, trace_len);
2893 }
2894
2895 b0->error = error_node->errors[error0];
2896
2897 /* verify speculative enqueue, maybe switch current next frame */
2898 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2899 n_left_to_next, bi0, next0);
2900 }
2901 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002902 }
Ole Troan944f5482016-05-24 11:56:58 +02002903 return frame->n_vectors;
2904}
2905
Dave Barachd7cb1b52016-12-09 09:52:16 -05002906/* *INDENT-OFF* */
2907VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2908{
Ole Troan944f5482016-05-24 11:56:58 +02002909 .function = ip6_hop_by_hop,
2910 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002911 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002912 .vector_size = sizeof (u32),
2913 .format_trace = format_ip6_hop_by_hop_trace,
2914 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002915 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002916 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002917 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002918};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002919/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002920
Dave Barach5331c722016-08-17 11:54:30 -04002921VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002922
2923static clib_error_t *
2924ip6_hop_by_hop_init (vlib_main_t * vm)
2925{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002926 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2927 memset (hm->options, 0, sizeof (hm->options));
2928 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002929 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002930 return (0);
2931}
2932
2933VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2934
Dave Barachd7cb1b52016-12-09 09:52:16 -05002935void
2936ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002937{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002939
2940 hm->next_override = next;
2941}
2942
Ole Troan944f5482016-05-24 11:56:58 +02002943int
2944ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002945 int options (vlib_buffer_t * b, ip6_header_t * ip,
2946 ip6_hop_by_hop_option_t * opt),
2947 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002948{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002949 ip6_main_t *im = &ip6_main;
2950 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002951
2952 ASSERT (option < ARRAY_LEN (hm->options));
2953
2954 /* Already registered */
2955 if (hm->options[option])
2956 return (-1);
2957
2958 hm->options[option] = options;
2959 hm->trace[option] = trace;
2960
2961 /* Set global variable */
2962 im->hbh_enabled = 1;
2963
2964 return (0);
2965}
2966
2967int
2968ip6_hbh_unregister_option (u8 option)
2969{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002970 ip6_main_t *im = &ip6_main;
2971 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002972
2973 ASSERT (option < ARRAY_LEN (hm->options));
2974
2975 /* Not registered */
2976 if (!hm->options[option])
2977 return (-1);
2978
2979 hm->options[option] = NULL;
2980 hm->trace[option] = NULL;
2981
2982 /* Disable global knob if this was the last option configured */
2983 int i;
2984 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002985 for (i = 0; i < 256; i++)
2986 {
2987 if (hm->options[option])
2988 {
2989 found = true;
2990 break;
2991 }
Ole Troan944f5482016-05-24 11:56:58 +02002992 }
Ole Troan944f5482016-05-24 11:56:58 +02002993 if (!found)
2994 im->hbh_enabled = 0;
2995
2996 return (0);
2997}
2998
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999/* Global IP6 main. */
3000ip6_main_t ip6_main;
3001
3002static clib_error_t *
3003ip6_lookup_init (vlib_main_t * vm)
3004{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003005 ip6_main_t *im = &ip6_main;
3006 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003007 uword i;
3008
Damjan Marion8b3191e2016-11-09 19:54:20 +01003009 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
3010 return error;
3011
Ed Warnickecb9cada2015-12-08 15:45:58 -07003012 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
3013 {
3014 u32 j, i0, i1;
3015
3016 i0 = i / 32;
3017 i1 = i % 32;
3018
3019 for (j = 0; j < i0; j++)
3020 im->fib_masks[i].as_u32[j] = ~0;
3021
3022 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003023 im->fib_masks[i].as_u32[i0] =
3024 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025 }
3026
3027 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
3028
3029 if (im->lookup_table_nbuckets == 0)
3030 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
3031
Dave Barachd7cb1b52016-12-09 09:52:16 -05003032 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003033
3034 if (im->lookup_table_size == 0)
3035 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04003036
Dave Barachd7cb1b52016-12-09 09:52:16 -05003037 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
3038 "ip6 FIB fwding table",
3039 im->lookup_table_nbuckets, im->lookup_table_size);
3040 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
3041 "ip6 FIB non-fwding table",
3042 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003043
Ed Warnickecb9cada2015-12-08 15:45:58 -07003044 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07003045 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3046 FIB_SOURCE_DEFAULT_ROUTE);
3047 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3048 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003049
3050 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003051 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052 pn = pg_get_node (ip6_lookup_node.index);
3053 pn->unformat_edit = unformat_pg_ip6_header;
3054 }
3055
Ole Troan944f5482016-05-24 11:56:58 +02003056 /* Unless explicitly configured, don't process HBH options */
3057 im->hbh_enabled = 0;
3058
Ed Warnickecb9cada2015-12-08 15:45:58 -07003059 {
3060 icmp6_neighbor_solicitation_header_t p;
3061
3062 memset (&p, 0, sizeof (p));
3063
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064 p.ip.ip_version_traffic_class_and_flow_label =
3065 clib_host_to_net_u32 (0x6 << 28);
3066 p.ip.payload_length =
3067 clib_host_to_net_u16 (sizeof (p) -
3068 STRUCT_OFFSET_OF
3069 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070 p.ip.protocol = IP_PROTOCOL_ICMP6;
3071 p.ip.hop_limit = 255;
3072 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3073
3074 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3075
Dave Barachd7cb1b52016-12-09 09:52:16 -05003076 p.link_layer_option.header.type =
3077 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3078 p.link_layer_option.header.n_data_u64s =
3079 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003080
3081 vlib_packet_template_init (vm,
3082 &im->discover_neighbor_packet_template,
3083 &p, sizeof (p),
3084 /* alloc chunk size */ 8,
3085 "ip6 neighbor discovery");
3086 }
3087
Dave Barach203c6322016-06-26 10:29:03 -04003088 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003089}
3090
3091VLIB_INIT_FUNCTION (ip6_lookup_init);
3092
Dave Barach75fc8542016-10-11 16:16:02 -04003093void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003094ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3095 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003096{
3097 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3098 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003099 ip->as_u8[8] = mac[0] ^ (1 << 1);
3100 ip->as_u8[9] = mac[1];
3101 ip->as_u8[10] = mac[2];
3102 ip->as_u8[11] = 0xFF;
3103 ip->as_u8[12] = 0xFE;
3104 ip->as_u8[13] = mac[3];
3105 ip->as_u8[14] = mac[4];
3106 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003107}
3108
Dave Barach75fc8542016-10-11 16:16:02 -04003109void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003110ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3111 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003112{
3113 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003114 mac[0] = ip->as_u8[8] ^ (1 << 1);
3115 mac[1] = ip->as_u8[9];
3116 mac[2] = ip->as_u8[10];
3117 mac[3] = ip->as_u8[13];
3118 mac[4] = ip->as_u8[14];
3119 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120}
3121
Dave Barach75fc8542016-10-11 16:16:02 -04003122static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003124 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003125{
3126 u8 mac[6];
3127 ip6_address_t _a, *a = &_a;
3128
3129 if (unformat (input, "%U", unformat_ethernet_address, mac))
3130 {
3131 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003132 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003133 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3134 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003135 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003136 }
Dave Barach75fc8542016-10-11 16:16:02 -04003137
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138 return 0;
3139}
3140
Billy McFall0683c9c2016-10-13 08:27:31 -04003141/*?
3142 * This command converts the given MAC Address into an IPv6 link-local
3143 * address.
3144 *
3145 * @cliexpar
3146 * Example of how to create an IPv6 link-local address:
3147 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3148 * Link local address: fe80::14d9:e0ff:fe91:7986
3149 * Original MAC address: 16:d9:e0:91:79:86
3150 * @cliexend
3151?*/
3152/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003153VLIB_CLI_COMMAND (test_link_command, static) =
3154{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003155 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003156 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003157 .short_help = "test ip6 link <mac-address>",
3158};
Billy McFall0683c9c2016-10-13 08:27:31 -04003159/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003160
Dave Barachd7cb1b52016-12-09 09:52:16 -05003161int
3162vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163{
Neale Ranns107e7d42017-04-11 09:55:19 -07003164 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003165
Neale Ranns107e7d42017-04-11 09:55:19 -07003166 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167
Neale Ranns107e7d42017-04-11 09:55:19 -07003168 if (~0 == fib_index)
3169 return VNET_API_ERROR_NO_SUCH_FIB;
3170
Neale Ranns227038a2017-04-21 01:07:59 -07003171 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3172 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003173
Neale Ranns227038a2017-04-21 01:07:59 -07003174 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175}
3176
3177static clib_error_t *
3178set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003179 unformat_input_t * input,
3180 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003181{
3182 int matched = 0;
3183 u32 table_id = 0;
3184 u32 flow_hash_config = 0;
3185 int rv;
3186
Dave Barachd7cb1b52016-12-09 09:52:16 -05003187 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3188 {
3189 if (unformat (input, "table %d", &table_id))
3190 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003191#define _(a,v) \
3192 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003193 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003194#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003195 else
3196 break;
3197 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003198
3199 if (matched == 0)
3200 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003201 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003202
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3204 switch (rv)
3205 {
Neale Ranns227038a2017-04-21 01:07:59 -07003206 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003207 break;
3208
3209 case -1:
3210 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003211
Ed Warnickecb9cada2015-12-08 15:45:58 -07003212 default:
3213 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3214 break;
3215 }
Dave Barach75fc8542016-10-11 16:16:02 -04003216
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217 return 0;
3218}
3219
Billy McFall0683c9c2016-10-13 08:27:31 -04003220/*?
3221 * Configure the set of IPv6 fields used by the flow hash.
3222 *
3223 * @cliexpar
3224 * @parblock
3225 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003226 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3227 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003228 * Example of display the configured flow hash:
3229 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003230 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3231 * @::/0
3232 * unicast-ip6-chain
3233 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3234 * [0] [@0]: dpo-drop ip6
3235 * fe80::/10
3236 * unicast-ip6-chain
3237 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3238 * [0] [@2]: dpo-receive
3239 * ff02::1/128
3240 * unicast-ip6-chain
3241 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3242 * [0] [@2]: dpo-receive
3243 * ff02::2/128
3244 * unicast-ip6-chain
3245 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3246 * [0] [@2]: dpo-receive
3247 * ff02::16/128
3248 * unicast-ip6-chain
3249 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3250 * [0] [@2]: dpo-receive
3251 * ff02::1:ff00:0/104
3252 * unicast-ip6-chain
3253 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3254 * [0] [@2]: dpo-receive
3255 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3256 * @::/0
3257 * unicast-ip6-chain
3258 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3259 * [0] [@0]: dpo-drop ip6
3260 * @::a:1:1:0:4/126
3261 * unicast-ip6-chain
3262 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3263 * [0] [@4]: ipv6-glean: af_packet0
3264 * @::a:1:1:0:7/128
3265 * unicast-ip6-chain
3266 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3267 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3268 * fe80::/10
3269 * unicast-ip6-chain
3270 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3271 * [0] [@2]: dpo-receive
3272 * fe80::fe:3eff:fe3e:9222/128
3273 * unicast-ip6-chain
3274 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3275 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3276 * ff02::1/128
3277 * unicast-ip6-chain
3278 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3279 * [0] [@2]: dpo-receive
3280 * ff02::2/128
3281 * unicast-ip6-chain
3282 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3283 * [0] [@2]: dpo-receive
3284 * ff02::16/128
3285 * unicast-ip6-chain
3286 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3287 * [0] [@2]: dpo-receive
3288 * ff02::1:ff00:0/104
3289 * unicast-ip6-chain
3290 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3291 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003292 * @cliexend
3293 * @endparblock
3294?*/
3295/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003296VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3297{
3298 .path = "set ip6 flow-hash",
3299 .short_help =
3300 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3301 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003302};
Billy McFall0683c9c2016-10-13 08:27:31 -04003303/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003304
3305static clib_error_t *
3306show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003307 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003308{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003309 ip6_main_t *im = &ip6_main;
3310 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003311 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003312
Ed Warnickecb9cada2015-12-08 15:45:58 -07003313 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003314 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003315 {
3316 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02003317 {
3318
3319 u32 node_index = vlib_get_node (vm,
3320 ip6_local_node.index)->
3321 next_nodes[lm->local_next_by_ip_protocol[i]];
3322 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3323 node_index);
3324 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003325 }
3326 return 0;
3327}
3328
3329
3330
Billy McFall0683c9c2016-10-13 08:27:31 -04003331/*?
3332 * Display the set of protocols handled by the local IPv6 stack.
3333 *
3334 * @cliexpar
3335 * Example of how to display local protocol table:
3336 * @cliexstart{show ip6 local}
3337 * Protocols handled by ip6_local
3338 * 17
3339 * 43
3340 * 58
3341 * 115
3342 * @cliexend
3343?*/
3344/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003345VLIB_CLI_COMMAND (show_ip6_local, static) =
3346{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003347 .path = "show ip6 local",
3348 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003349 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003350};
Billy McFall0683c9c2016-10-13 08:27:31 -04003351/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003352
Dave Barachd7cb1b52016-12-09 09:52:16 -05003353int
3354vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3355 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003356{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003357 vnet_main_t *vnm = vnet_get_main ();
3358 vnet_interface_main_t *im = &vnm->interface_main;
3359 ip6_main_t *ipm = &ip6_main;
3360 ip_lookup_main_t *lm = &ipm->lookup_main;
3361 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003362 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003363
3364 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3365 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3366
3367 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3368 return VNET_API_ERROR_NO_SUCH_ENTRY;
3369
3370 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003371 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003372
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003373 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003374
3375 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003376 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003377 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003378 .fp_len = 128,
3379 .fp_proto = FIB_PROTOCOL_IP6,
3380 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003381 };
3382 u32 fib_index;
3383
Dave Barachd7cb1b52016-12-09 09:52:16 -05003384 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3385 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003386
3387
Dave Barachd7cb1b52016-12-09 09:52:16 -05003388 if (table_index != (u32) ~ 0)
3389 {
3390 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003391
Dave Barachd7cb1b52016-12-09 09:52:16 -05003392 dpo_set (&dpo,
3393 DPO_CLASSIFY,
3394 DPO_PROTO_IP6,
3395 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003396
Dave Barachd7cb1b52016-12-09 09:52:16 -05003397 fib_table_entry_special_dpo_add (fib_index,
3398 &pfx,
3399 FIB_SOURCE_CLASSIFY,
3400 FIB_ENTRY_FLAG_NONE, &dpo);
3401 dpo_reset (&dpo);
3402 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003403 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003404 {
3405 fib_table_entry_special_remove (fib_index,
3406 &pfx, FIB_SOURCE_CLASSIFY);
3407 }
3408 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003409
Ed Warnickecb9cada2015-12-08 15:45:58 -07003410 return 0;
3411}
3412
3413static clib_error_t *
3414set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003415 unformat_input_t * input,
3416 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003417{
3418 u32 table_index = ~0;
3419 int table_index_set = 0;
3420 u32 sw_if_index = ~0;
3421 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003422
Dave Barachd7cb1b52016-12-09 09:52:16 -05003423 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3424 {
3425 if (unformat (input, "table-index %d", &table_index))
3426 table_index_set = 1;
3427 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3428 vnet_get_main (), &sw_if_index))
3429 ;
3430 else
3431 break;
3432 }
Dave Barach75fc8542016-10-11 16:16:02 -04003433
Ed Warnickecb9cada2015-12-08 15:45:58 -07003434 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003435 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003436
Ed Warnickecb9cada2015-12-08 15:45:58 -07003437 if (sw_if_index == ~0)
3438 return clib_error_return (0, "interface / subif must be specified");
3439
3440 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3441
3442 switch (rv)
3443 {
3444 case 0:
3445 break;
3446
3447 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3448 return clib_error_return (0, "No such interface");
3449
3450 case VNET_API_ERROR_NO_SUCH_ENTRY:
3451 return clib_error_return (0, "No such classifier table");
3452 }
3453 return 0;
3454}
3455
Billy McFall0683c9c2016-10-13 08:27:31 -04003456/*?
3457 * Assign a classification table to an interface. The classification
3458 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3459 * commands. Once the table is create, use this command to filter packets
3460 * on an interface.
3461 *
3462 * @cliexpar
3463 * Example of how to assign a classification table to an interface:
3464 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3465?*/
3466/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003467VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3468{
3469 .path = "set ip6 classify",
3470 .short_help =
3471 "set ip6 classify intfc <interface> table-index <classify-idx>",
3472 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003473};
Billy McFall0683c9c2016-10-13 08:27:31 -04003474/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003475
3476static clib_error_t *
3477ip6_config (vlib_main_t * vm, unformat_input_t * input)
3478{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003479 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003480 uword heapsize = 0;
3481 u32 tmp;
3482 u32 nbuckets = 0;
3483
Dave Barachd7cb1b52016-12-09 09:52:16 -05003484 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3485 {
3486 if (unformat (input, "hash-buckets %d", &tmp))
3487 nbuckets = tmp;
3488 else if (unformat (input, "heap-size %dm", &tmp))
3489 heapsize = ((u64) tmp) << 20;
3490 else if (unformat (input, "heap-size %dM", &tmp))
3491 heapsize = ((u64) tmp) << 20;
3492 else if (unformat (input, "heap-size %dg", &tmp))
3493 heapsize = ((u64) tmp) << 30;
3494 else if (unformat (input, "heap-size %dG", &tmp))
3495 heapsize = ((u64) tmp) << 30;
3496 else
3497 return clib_error_return (0, "unknown input '%U'",
3498 format_unformat_error, input);
3499 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003500
3501 im->lookup_table_nbuckets = nbuckets;
3502 im->lookup_table_size = heapsize;
3503
3504 return 0;
3505}
3506
3507VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003508
3509/*
3510 * fd.io coding-style-patch-verification: ON
3511 *
3512 * Local Variables:
3513 * eval: (c-set-style "gnu")
3514 * End:
3515 */