blob: c1c9ec0b5860bb8fd83dd1665f59764916746a7a [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 Ranns8269d3d2018-01-30 09:02:20 -0800439 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Neale Ranns630198f2017-05-22 09:20:20 -0400440 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100441
Neale Ranns8269d3d2018-01-30 09:02:20 -0800442 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
443 sw_if_index, !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
Neale Ranns8269d3d2018-01-30 09:02:20 -0800625VNET_FEATURE_INIT (ip6_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500626{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100627 .arc_name = "ip6-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800628 .node_name = "ip6-not-enabled",
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
Neale Ranns8269d3d2018-01-30 09:02:20 -0800653VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
Damjan Marion8b3191e2016-11-09 19:54:20 +0100654 .arc_name = "ip6-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800655 .node_name = "ip6-not-enabled",
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",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800669 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
Damjan Marion8b3191e2016-11-09 19:54:20 +0100670 .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
Neale Ranns8269d3d2018-01-30 09:02:20 -0800714 vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +0100715 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Neale Ranns8269d3d2018-01-30 09:02:20 -0800717 vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
718 sw_if_index, 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
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001344 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001345 || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1346 || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001347 != 0;
1348 good_l4_csum1 = (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001349 || (flags1 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1350 || flags1 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001351 != 0;
Shwethab78292e2016-09-13 11:51:00 +01001352 len_diff0 = 0;
1353 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354
rootc9d1c5b2017-08-15 12:58:31 -04001355 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001356 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001357 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001358 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001359 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001360 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001361 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001362 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1363 {
1364 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1365 udp_len0 = clib_net_to_host_u16 (udp0->length);
1366 len_diff0 = ip_len0 - udp_len0;
1367 }
Shwethab78292e2016-09-13 11:51:00 +01001368 }
rootc9d1c5b2017-08-15 12:58:31 -04001369 if (PREDICT_TRUE (is_tcp_udp1))
Shwethab78292e2016-09-13 11:51:00 +01001370 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001371 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001372 /* Don't verify UDP checksum for packets with explicit zero checksum. */
rootc9d1c5b2017-08-15 12:58:31 -04001373 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001374 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001375 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001376 if (is_tcp_udp1 == IP_PROTOCOL_UDP)
1377 {
1378 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1379 udp_len1 = clib_net_to_host_u16 (udp1->length);
1380 len_diff1 = ip_len1 - udp_len1;
1381 }
Shwethab78292e2016-09-13 11:51:00 +01001382 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001383
rootc9d1c5b2017-08-15 12:58:31 -04001384 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1385 good_l4_csum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1388 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1389
1390 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001391 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001392 && !(flags0 &
1393 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 {
1395 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001396 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001397 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398 }
1399 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001400 && !good_l4_csum1
Damjan Marion213b5aa2017-07-13 21:19:27 +02001401 && !(flags1 &
1402 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403 {
1404 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
rootc9d1c5b2017-08-15 12:58:31 -04001405 good_l4_csum1 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001406 (flags1 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001407 }
1408
1409 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1411 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1412
Dave Barachd7cb1b52016-12-09 09:52:16 -05001413 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1414 IP6_ERROR_UDP_CHECKSUM);
1415 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1416 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001417 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1418 error1 = (!good_l4_csum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
1420 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001421 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001422 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1423 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001424 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301426 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001427 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001428 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001429 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1430 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001431 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301433 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001434 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001435 }
1436
Florin Corascea194d2017-10-02 00:18:51 -07001437 /* TODO maybe move to lookup? */
1438 vnet_buffer (p0)->ip.fib_index =
1439 vec_elt (im->fib_index_by_sw_if_index,
1440 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1441 vnet_buffer (p0)->ip.fib_index =
1442 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1443 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1444 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1445
1446 vnet_buffer (p1)->ip.fib_index =
1447 vec_elt (im->fib_index_by_sw_if_index,
1448 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
1449 vnet_buffer (p1)->ip.fib_index =
1450 (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1451 (u32) ~ 0) ? vnet_buffer (p1)->ip.
1452 fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1453
1454
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001455 skip_checks:
1456
1457 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1458 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1459
Dave Barachd7cb1b52016-12-09 09:52:16 -05001460 next0 =
1461 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1462 next1 =
1463 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001464
1465 p0->error = error_node->errors[error0];
1466 p1->error = error_node->errors[error1];
1467
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001468 if (head_of_feature_arc)
1469 {
1470 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1471 vnet_feature_arc_start (arc_index,
1472 vnet_buffer (p0)->sw_if_index
1473 [VLIB_RX], &next0, p0);
1474 if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1475 vnet_feature_arc_start (arc_index,
1476 vnet_buffer (p1)->sw_if_index
1477 [VLIB_RX], &next1, p1);
1478 }
1479
Ed Warnickecb9cada2015-12-08 15:45:58 -07001480 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1481 to_next, n_left_to_next,
1482 pi0, pi1, next0, next1);
1483 }
1484
1485 while (n_left_from > 0 && n_left_to_next > 0)
1486 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001487 vlib_buffer_t *p0;
1488 ip6_header_t *ip0;
1489 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490 u32 pi0, ip_len0, udp_len0, flags0, next0;
1491 i32 len_diff0;
rootc9d1c5b2017-08-15 12:58:31 -04001492 u8 error0, type0, good_l4_csum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001493 u32 udp_offset0;
rootc9d1c5b2017-08-15 12:58:31 -04001494 u8 is_tcp_udp0;
Dave Barach75fc8542016-10-11 16:16:02 -04001495
Ed Warnickecb9cada2015-12-08 15:45:58 -07001496 pi0 = to_next[0] = from[0];
1497 from += 1;
1498 n_left_from -= 1;
1499 to_next += 1;
1500 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001501
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001502 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1503
Ed Warnickecb9cada2015-12-08 15:45:58 -07001504 p0 = vlib_get_buffer (vm, pi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001505 ip0 = vlib_buffer_get_current (p0);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001506
1507 if (head_of_feature_arc == 0)
1508 goto skip_check;
1509
Damjan Marion072401e2017-07-13 18:53:27 +02001510 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001511
Ed Warnickecb9cada2015-12-08 15:45:58 -07001512 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513 flags0 = p0->flags;
rootc9d1c5b2017-08-15 12:58:31 -04001514 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001515 good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
Jakub Grajciar2eeeb4b2017-11-07 14:39:10 +01001516 || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1517 || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
Jakub Grajciar96be8e82017-10-30 14:56:17 +01001518 != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001519
Shwethab78292e2016-09-13 11:51:00 +01001520 len_diff0 = 0;
rootc9d1c5b2017-08-15 12:58:31 -04001521 if (PREDICT_TRUE (is_tcp_udp0))
Shwethab78292e2016-09-13 11:51:00 +01001522 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001523 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
rootc9d1c5b2017-08-15 12:58:31 -04001524 /* Don't verify UDP checksum for packets with explicit zero
1525 * checksum. */
1526 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001527 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001528 /* Verify UDP length. */
rootc9d1c5b2017-08-15 12:58:31 -04001529 if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1530 {
1531 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1532 udp_len0 = clib_net_to_host_u16 (udp0->length);
1533 len_diff0 = ip_len0 - udp_len0;
1534 }
Shwethab78292e2016-09-13 11:51:00 +01001535 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001536
rootc9d1c5b2017-08-15 12:58:31 -04001537 good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001538 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1539
1540 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
rootc9d1c5b2017-08-15 12:58:31 -04001541 && !good_l4_csum0
Damjan Marion213b5aa2017-07-13 21:19:27 +02001542 && !(flags0 &
1543 VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544 {
1545 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
rootc9d1c5b2017-08-15 12:58:31 -04001546 good_l4_csum0 =
Damjan Marion213b5aa2017-07-13 21:19:27 +02001547 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548 }
1549
1550 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001551 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1552
Dave Barachd7cb1b52016-12-09 09:52:16 -05001553 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1554 IP6_ERROR_UDP_CHECKSUM);
1555 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1556 IP6_ERROR_ICMP_CHECKSUM);
rootc9d1c5b2017-08-15 12:58:31 -04001557 error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001558
rootc9d1c5b2017-08-15 12:58:31 -04001559 /* If this is a neighbor solicitation (ICMP), skip src RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001560 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1561 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001562 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301564 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001565 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001566 }
1567
Florin Corascea194d2017-10-02 00:18:51 -07001568 vnet_buffer (p0)->ip.fib_index =
1569 vec_elt (im->fib_index_by_sw_if_index,
1570 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1571 vnet_buffer (p0)->ip.fib_index =
1572 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1573 (u32) ~ 0) ? vnet_buffer (p0)->ip.
1574 fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1575
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001576 skip_check:
1577
1578 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001579 next0 =
1580 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001581 p0->error = error_node->errors[error0];
1582
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001583 if (head_of_feature_arc)
1584 {
1585 if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1586 vnet_feature_arc_start (arc_index,
1587 vnet_buffer (p0)->sw_if_index
1588 [VLIB_RX], &next0, p0);
1589 }
1590
Ed Warnickecb9cada2015-12-08 15:45:58 -07001591 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1592 to_next, n_left_to_next,
1593 pi0, next0);
1594 }
Dave Barach75fc8542016-10-11 16:16:02 -04001595
Ed Warnickecb9cada2015-12-08 15:45:58 -07001596 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1597 }
1598
1599 return frame->n_vectors;
1600}
1601
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001602static uword
1603ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1604{
1605 return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1606}
1607
Dave Barachd7cb1b52016-12-09 09:52:16 -05001608/* *INDENT-OFF* */
1609VLIB_REGISTER_NODE (ip6_local_node, static) =
1610{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611 .function = ip6_local,
1612 .name = "ip6-local",
1613 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001614 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001616 .next_nodes =
1617 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001618 [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1619 [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001620 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1621 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1622 },
1623};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001624/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625
Dave Barachd7cb1b52016-12-09 09:52:16 -05001626VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001627
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001628
1629static uword
1630ip6_local_end_of_arc (vlib_main_t * vm,
1631 vlib_node_runtime_t * node, vlib_frame_t * frame)
1632{
1633 return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1634}
1635
1636/* *INDENT-OFF* */
1637VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
1638 .function = ip6_local_end_of_arc,
1639 .name = "ip6-local-end-of-arc",
1640 .vector_size = sizeof (u32),
1641
1642 .format_trace = format_ip6_forward_next_trace,
1643 .sibling_of = "ip6-local",
1644};
1645
1646VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
1647
1648VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1649 .arc_name = "ip6-local",
1650 .node_name = "ip6-local-end-of-arc",
1651 .runs_before = 0, /* not before any other features */
1652};
1653/* *INDENT-ON* */
1654
Dave Barachd7cb1b52016-12-09 09:52:16 -05001655void
1656ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001657{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001658 vlib_main_t *vm = vlib_get_main ();
1659 ip6_main_t *im = &ip6_main;
1660 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001661
1662 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001663 lm->local_next_by_ip_protocol[protocol] =
1664 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001665}
1666
Dave Barachd7cb1b52016-12-09 09:52:16 -05001667typedef enum
1668{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001669 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001670 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001671 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1672} ip6_discover_neighbor_next_t;
1673
Dave Barachd7cb1b52016-12-09 09:52:16 -05001674typedef enum
1675{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001676 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1677 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001678 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001679} ip6_discover_neighbor_error_t;
1680
1681static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001682ip6_discover_neighbor_inline (vlib_main_t * vm,
1683 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001684 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001686 vnet_main_t *vnm = vnet_get_main ();
1687 ip6_main_t *im = &ip6_main;
1688 ip_lookup_main_t *lm = &im->lookup_main;
1689 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001690 uword n_left_from, n_left_to_next_drop;
1691 static f64 time_last_seed_change = -1e100;
1692 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001693 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001694 f64 time_now;
1695 int bogus_length;
1696
1697 if (node->flags & VLIB_NODE_FLAG_TRACE)
1698 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1699
1700 time_now = vlib_time_now (vm);
1701 if (time_now - time_last_seed_change > 1e-3)
1702 {
1703 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001704 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1705 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001706 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1707 hash_seeds[i] = r[i];
1708
1709 /* Mark all hash keys as been not-seen before. */
1710 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1711 hash_bitmap[i] = 0;
1712
1713 time_last_seed_change = time_now;
1714 }
1715
1716 from = vlib_frame_vector_args (frame);
1717 n_left_from = frame->n_vectors;
1718
1719 while (n_left_from > 0)
1720 {
1721 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1722 to_next_drop, n_left_to_next_drop);
1723
1724 while (n_left_from > 0 && n_left_to_next_drop > 0)
1725 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001726 vlib_buffer_t *p0;
1727 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001728 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1729 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001730 ip_adjacency_t *adj0;
1731 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001732 u32 next0;
1733
1734 pi0 = from[0];
1735
1736 p0 = vlib_get_buffer (vm, pi0);
1737
1738 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1739
1740 ip0 = vlib_buffer_get_current (p0);
1741
Neale Ranns107e7d42017-04-11 09:55:19 -07001742 adj0 = adj_get (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001744 if (!is_glean)
1745 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001746 ip0->dst_address.as_u64[0] =
1747 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1748 ip0->dst_address.as_u64[1] =
1749 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001750 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001751
Ed Warnickecb9cada2015-12-08 15:45:58 -07001752 a0 = hash_seeds[0];
1753 b0 = hash_seeds[1];
1754 c0 = hash_seeds[2];
1755
1756 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1757 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1758
1759 a0 ^= sw_if_index0;
1760 b0 ^= ip0->dst_address.as_u32[0];
1761 c0 ^= ip0->dst_address.as_u32[1];
1762
1763 hash_v3_mix32 (a0, b0, c0);
1764
1765 b0 ^= ip0->dst_address.as_u32[2];
1766 c0 ^= ip0->dst_address.as_u32[3];
1767
1768 hash_v3_finalize32 (a0, b0, c0);
1769
1770 c0 &= BITS (hash_bitmap) - 1;
1771 c0 = c0 / BITS (uword);
1772 m0 = (uword) 1 << (c0 % BITS (uword));
1773
1774 bm0 = hash_bitmap[c0];
1775 drop0 = (bm0 & m0) != 0;
1776
1777 /* Mark it as seen. */
1778 hash_bitmap[c0] = bm0 | m0;
1779
1780 from += 1;
1781 n_left_from -= 1;
1782 to_next_drop[0] = pi0;
1783 to_next_drop += 1;
1784 n_left_to_next_drop -= 1;
1785
Dave Barachd7cb1b52016-12-09 09:52:16 -05001786 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787
Dave Barachd7cb1b52016-12-09 09:52:16 -05001788 /* If the interface is link-down, drop the pkt */
1789 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1790 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001791
Dave Barach75fc8542016-10-11 16:16:02 -04001792 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001793 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1794 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001795 if (drop0)
1796 continue;
1797
Neale Rannsb80c5362016-10-08 13:03:40 +01001798 /*
1799 * the adj has been updated to a rewrite but the node the DPO that got
1800 * us here hasn't - yet. no big deal. we'll drop while we wait.
1801 */
1802 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1803 continue;
1804
Ed Warnickecb9cada2015-12-08 15:45:58 -07001805 {
1806 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001807 icmp6_neighbor_solicitation_header_t *h0;
1808 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001809
Dave Barach75fc8542016-10-11 16:16:02 -04001810 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001811 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001812
Dave Barach75fc8542016-10-11 16:16:02 -04001813 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001814 * Build ethernet header.
1815 * Choose source address based on destination lookup
1816 * adjacency.
1817 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001818 if (ip6_src_address_for_packet (lm,
1819 sw_if_index0,
1820 &h0->ip.src_address))
1821 {
1822 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 p0->error =
1824 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1825 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001826 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001827 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001828
Dave Barach75fc8542016-10-11 16:16:02 -04001829 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001830 * Destination address is a solicited node multicast address.
1831 * We need to fill in
1832 * the low 24 bits with low 24 bits of target's address.
1833 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001834 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1835 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1836 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1837
1838 h0->neighbor.target_address = ip0->dst_address;
1839
Dave Barach75fc8542016-10-11 16:16:02 -04001840 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001841 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001842
Dave Barachd7cb1b52016-12-09 09:52:16 -05001843 /* $$$$ appears we need this; why is the checksum non-zero? */
1844 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001845 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001846 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1847 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001848
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001850
1851 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1852 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001853 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001854 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855
1856 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001857 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1859
John Lod1f5d042016-04-12 18:20:39 -04001860 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861
1862 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1863 }
1864 }
1865
Dave Barach75fc8542016-10-11 16:16:02 -04001866 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001868 }
1869
1870 return frame->n_vectors;
1871}
1872
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001873static uword
1874ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001875 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001876{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001878}
1879
1880static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001881ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001882{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001884}
1885
Dave Barachd7cb1b52016-12-09 09:52:16 -05001886static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001888 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001889 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1890 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001891};
1892
Dave Barachd7cb1b52016-12-09 09:52:16 -05001893/* *INDENT-OFF* */
1894VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1895{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001896 .function = ip6_discover_neighbor,
1897 .name = "ip6-discover-neighbor",
1898 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001899 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001900 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1901 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001903 .next_nodes =
1904 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08001905 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
John Lod1f5d042016-04-12 18:20:39 -04001906 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907 },
1908};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001909/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910
Dave Barachd7cb1b52016-12-09 09:52:16 -05001911/* *INDENT-OFF* */
1912VLIB_REGISTER_NODE (ip6_glean_node) =
1913{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001914 .function = ip6_glean,
1915 .name = "ip6-glean",
1916 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001917 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001918 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1919 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001920 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001921 .next_nodes =
1922 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08001923 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001924 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1925 },
1926};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001927/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001928
Ed Warnickecb9cada2015-12-08 15:45:58 -07001929clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001930ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1931{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001932 vnet_main_t *vnm = vnet_get_main ();
1933 ip6_main_t *im = &ip6_main;
1934 icmp6_neighbor_solicitation_header_t *h;
1935 ip6_address_t *src;
1936 ip_interface_address_t *ia;
1937 ip_adjacency_t *adj;
1938 vnet_hw_interface_t *hi;
1939 vnet_sw_interface_t *si;
1940 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07001941 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001942 u32 bi = 0;
1943 int bogus_length;
1944
1945 si = vnet_get_sw_interface (vnm, sw_if_index);
1946
1947 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1948 {
1949 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001950 format_ip6_address, dst,
1951 format_vnet_sw_if_index_name, vnm,
1952 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001953 }
1954
Dave Barachd7cb1b52016-12-09 09:52:16 -05001955 src =
1956 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1957 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958 {
1959 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001960 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001961 (0, "no matching interface address for destination %U (interface %U)",
1962 format_ip6_address, dst,
1963 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001964 }
1965
Dave Barachd7cb1b52016-12-09 09:52:16 -05001966 h =
1967 vlib_packet_template_get_packet (vm,
1968 &im->discover_neighbor_packet_template,
1969 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001970
1971 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1972
1973 /* Destination address is a solicited node multicast address. We need to fill in
1974 the low 24 bits with low 24 bits of target's address. */
1975 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1976 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1977 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1978
1979 h->ip.src_address = src[0];
1980 h->neighbor.target_address = dst[0];
1981
Pavel Kotucek57808982017-08-02 08:20:19 +02001982 if (PREDICT_FALSE (!hi->hw_address))
1983 {
1984 return clib_error_return (0, "%U: interface %U do not support ip probe",
1985 format_ip6_address, dst,
1986 format_vnet_sw_if_index_name, vnm,
1987 sw_if_index);
1988 }
1989
Dave Barachd7cb1b52016-12-09 09:52:16 -05001990 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1991 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001992
Dave Barach75fc8542016-10-11 16:16:02 -04001993 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001995 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001996
1997 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001998 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1999 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002000
2001 /* Add encapsulation string for software interface (e.g. ethernet header). */
Neale Ranns7a272742017-05-30 02:08:14 -07002002 ip46_address_t nh = {
2003 .ip6 = *dst,
2004 };
2005
2006 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
2007 VNET_LINK_IP6, &nh, sw_if_index);
2008 adj = adj_get (ai);
2009
Dave Barach59b25652017-09-10 15:04:27 -04002010 /* Peer has been previously resolved, retrieve glean adj instead */
2011 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2012 {
2013 adj_unlock (ai);
2014 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6, sw_if_index, &nh);
2015 adj = adj_get (ai);
2016 }
2017
Ed Warnickecb9cada2015-12-08 15:45:58 -07002018 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
2019 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2020
2021 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002022 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2023 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002024 to_next[0] = bi;
2025 f->n_vectors = 1;
2026 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2027 }
2028
Neale Ranns7a272742017-05-30 02:08:14 -07002029 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002030 return /* no error */ 0;
2031}
2032
Dave Barachd7cb1b52016-12-09 09:52:16 -05002033typedef enum
2034{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002035 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002036 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037} ip6_rewrite_next_t;
2038
2039always_inline uword
2040ip6_rewrite_inline (vlib_main_t * vm,
2041 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002042 vlib_frame_t * frame,
2043 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002045 ip_lookup_main_t *lm = &ip6_main.lookup_main;
2046 u32 *from = vlib_frame_vector_args (frame);
2047 u32 n_left_from, n_left_to_next, *to_next, next_index;
2048 vlib_node_runtime_t *error_node =
2049 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002050
2051 n_left_from = frame->n_vectors;
2052 next_index = node->cached_next_index;
Damjan Marion586afd72017-04-05 19:18:20 +02002053 u32 thread_index = vlib_get_thread_index ();
Dave Barach75fc8542016-10-11 16:16:02 -04002054
Ed Warnickecb9cada2015-12-08 15:45:58 -07002055 while (n_left_from > 0)
2056 {
2057 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2058
2059 while (n_left_from >= 4 && n_left_to_next >= 2)
2060 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002061 ip_adjacency_t *adj0, *adj1;
2062 vlib_buffer_t *p0, *p1;
2063 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002064 u32 pi0, rw_len0, next0, error0, adj_index0;
2065 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002066 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04002067
Ed Warnickecb9cada2015-12-08 15:45:58 -07002068 /* Prefetch next iteration. */
2069 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002070 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002071
2072 p2 = vlib_get_buffer (vm, from[2]);
2073 p3 = vlib_get_buffer (vm, from[3]);
2074
2075 vlib_prefetch_buffer_header (p2, LOAD);
2076 vlib_prefetch_buffer_header (p3, LOAD);
2077
2078 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2079 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2080
2081 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2082 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2083 }
2084
2085 pi0 = to_next[0] = from[0];
2086 pi1 = to_next[1] = from[1];
2087
2088 from += 2;
2089 n_left_from -= 2;
2090 to_next += 2;
2091 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002092
Ed Warnickecb9cada2015-12-08 15:45:58 -07002093 p0 = vlib_get_buffer (vm, pi0);
2094 p1 = vlib_get_buffer (vm, pi1);
2095
Neale Rannsf06aea52016-11-29 06:51:37 -08002096 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2097 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002098
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099 ip0 = vlib_buffer_get_current (p0);
2100 ip1 = vlib_buffer_get_current (p1);
2101
2102 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002103 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104
Damjan Marion213b5aa2017-07-13 21:19:27 +02002105 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002106 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002107 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002108
2109 /* Input node should have reject packets with hop limit 0. */
2110 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002111
2112 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113
2114 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002115
Dave Barachd7cb1b52016-12-09 09:52:16 -05002116 /*
2117 * If the hop count drops below 1 when forwarding, generate
2118 * an ICMP response.
2119 */
2120 if (PREDICT_FALSE (hop_limit0 <= 0))
2121 {
2122 error0 = IP6_ERROR_TIME_EXPIRED;
2123 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2124 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2125 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2126 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2127 0);
2128 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002129 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002130 else
2131 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002132 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002133 }
Damjan Marion213b5aa2017-07-13 21:19:27 +02002134 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002135 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002136 i32 hop_limit1 = ip1->hop_limit;
2137
2138 /* Input node should have reject packets with hop limit 0. */
2139 ASSERT (ip1->hop_limit > 0);
2140
2141 hop_limit1 -= 1;
2142
2143 ip1->hop_limit = hop_limit1;
2144
Dave Barachd7cb1b52016-12-09 09:52:16 -05002145 /*
2146 * If the hop count drops below 1 when forwarding, generate
2147 * an ICMP response.
2148 */
2149 if (PREDICT_FALSE (hop_limit1 <= 0))
2150 {
2151 error1 = IP6_ERROR_TIME_EXPIRED;
2152 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2153 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2154 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2155 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2156 0);
2157 }
2158 }
2159 else
2160 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002161 p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002162 }
Neale Ranns107e7d42017-04-11 09:55:19 -07002163 adj0 = adj_get (adj_index0);
2164 adj1 = adj_get (adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165
Ed Warnickecb9cada2015-12-08 15:45:58 -07002166 rw_len0 = adj0[0].rewrite_header.data_bytes;
2167 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002168 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2169 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170
Neale Ranns9c6a6132017-02-21 05:33:14 -08002171 if (do_counters)
2172 {
2173 vlib_increment_combined_counter
2174 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002175 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002176 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2177 vlib_increment_combined_counter
2178 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002179 thread_index, adj_index1, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002180 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2181 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002182
2183 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002184 error0 =
2185 (vlib_buffer_length_in_chain (vm, p0) >
2186 adj0[0].
2187 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2188 error0);
2189 error1 =
2190 (vlib_buffer_length_in_chain (vm, p1) >
2191 adj1[0].
2192 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2193 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002194
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195 /* Don't adjust the buffer for hop count issue; icmp-error node
2196 * wants to see the IP headerr */
2197 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2198 {
2199 p0->current_data -= rw_len0;
2200 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002201
Dave Barachd7cb1b52016-12-09 09:52:16 -05002202 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2203 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2204 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002205
Neale Rannsb069a692017-03-15 12:34:25 -04002206 if (PREDICT_FALSE
2207 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2208 vnet_feature_arc_start (lm->output_feature_arc_index,
2209 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002210 }
2211 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2212 {
2213 p1->current_data -= rw_len1;
2214 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002215
Dave Barachd7cb1b52016-12-09 09:52:16 -05002216 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2217 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2218 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002219
Neale Rannsb069a692017-03-15 12:34:25 -04002220 if (PREDICT_FALSE
2221 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2222 vnet_feature_arc_start (lm->output_feature_arc_index,
2223 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002224 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002225
2226 /* Guess we are only writing on simple Ethernet header. */
2227 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002228 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002229
Neale Ranns5e575b12016-10-03 09:40:25 +01002230 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002231 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08002232 adj0->sub_type.midchain.fixup_func
2233 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2234 adj1->sub_type.midchain.fixup_func
2235 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002236 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002237 if (is_mcast)
2238 {
2239 /*
2240 * copy bytes from the IP address into the MAC rewrite
2241 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002242 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2243 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002244 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002245
Ed Warnickecb9cada2015-12-08 15:45:58 -07002246 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2247 to_next, n_left_to_next,
2248 pi0, pi1, next0, next1);
2249 }
2250
2251 while (n_left_from > 0 && n_left_to_next > 0)
2252 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002253 ip_adjacency_t *adj0;
2254 vlib_buffer_t *p0;
2255 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002256 u32 pi0, rw_len0;
2257 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002258 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002259
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260 pi0 = to_next[0] = from[0];
2261
2262 p0 = vlib_get_buffer (vm, pi0);
2263
Neale Rannsf06aea52016-11-29 06:51:37 -08002264 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002265
Neale Ranns107e7d42017-04-11 09:55:19 -07002266 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002267
Ed Warnickecb9cada2015-12-08 15:45:58 -07002268 ip0 = vlib_buffer_get_current (p0);
2269
2270 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002271 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272
2273 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002274 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275 {
2276 i32 hop_limit0 = ip0->hop_limit;
2277
2278 ASSERT (ip0->hop_limit > 0);
2279
2280 hop_limit0 -= 1;
2281
2282 ip0->hop_limit = hop_limit0;
2283
Dave Barachd7cb1b52016-12-09 09:52:16 -05002284 if (PREDICT_FALSE (hop_limit0 <= 0))
2285 {
2286 /*
2287 * If the hop count drops below 1 when forwarding, generate
2288 * an ICMP response.
2289 */
2290 error0 = IP6_ERROR_TIME_EXPIRED;
2291 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2292 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2293 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2294 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2295 0);
2296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002297 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002298 else
2299 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002300 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002302
Ed Warnickecb9cada2015-12-08 15:45:58 -07002303 /* Guess we are only writing on simple Ethernet header. */
2304 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002305
Ed Warnickecb9cada2015-12-08 15:45:58 -07002306 /* Update packet buffer attributes/set output interface. */
2307 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002308 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002309
Neale Ranns9c6a6132017-02-21 05:33:14 -08002310 if (do_counters)
2311 {
2312 vlib_increment_combined_counter
2313 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002314 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002315 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2316 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002317
2318 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002319 error0 =
2320 (vlib_buffer_length_in_chain (vm, p0) >
2321 adj0[0].
2322 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2323 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324
Dave Barachd7cb1b52016-12-09 09:52:16 -05002325 /* Don't adjust the buffer for hop count issue; icmp-error node
2326 * wants to see the IP headerr */
2327 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2328 {
Chris Luke816f3e12016-06-14 16:24:47 -04002329 p0->current_data -= rw_len0;
2330 p0->current_length += rw_len0;
2331
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002333
Dave Barachd7cb1b52016-12-09 09:52:16 -05002334 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2335 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002336
Neale Rannsb069a692017-03-15 12:34:25 -04002337 if (PREDICT_FALSE
2338 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2339 vnet_feature_arc_start (lm->output_feature_arc_index,
2340 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002341 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342
Neale Ranns5e575b12016-10-03 09:40:25 +01002343 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002344 {
Neale Rannsdb14f5a2018-01-29 10:43:33 -08002345 adj0->sub_type.midchain.fixup_func
2346 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002347 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002348 if (is_mcast)
2349 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002350 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002351 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002352
Ed Warnickecb9cada2015-12-08 15:45:58 -07002353 p0->error = error_node->errors[error0];
2354
2355 from += 1;
2356 n_left_from -= 1;
2357 to_next += 1;
2358 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002359
Ed Warnickecb9cada2015-12-08 15:45:58 -07002360 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2361 to_next, n_left_to_next,
2362 pi0, next0);
2363 }
2364
2365 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2366 }
2367
2368 /* Need to do trace after rewrites to pick up new packet data. */
2369 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002370 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002371
2372 return frame->n_vectors;
2373}
2374
2375static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002376ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002377 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002378{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002379 if (adj_are_counters_enabled ())
2380 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2381 else
2382 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002383}
2384
2385static uword
2386ip6_rewrite_mcast (vlib_main_t * vm,
2387 vlib_node_runtime_t * node, vlib_frame_t * frame)
2388{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002389 if (adj_are_counters_enabled ())
2390 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2391 else
2392 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002393}
2394
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002395static uword
2396ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002397 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002398{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002399 if (adj_are_counters_enabled ())
2400 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2401 else
2402 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002403}
2404
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002405static uword
2406ip6_mcast_midchain (vlib_main_t * vm,
2407 vlib_node_runtime_t * node, vlib_frame_t * frame)
2408{
2409 if (adj_are_counters_enabled ())
2410 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2411 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002412 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002413}
2414
Dave Barachd7cb1b52016-12-09 09:52:16 -05002415/* *INDENT-OFF* */
2416VLIB_REGISTER_NODE (ip6_midchain_node) =
2417{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002418 .function = ip6_midchain,
2419 .name = "ip6-midchain",
2420 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002421 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002422 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002423 };
2424/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002425
Dave Barachd7cb1b52016-12-09 09:52:16 -05002426VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002427
Dave Barachd7cb1b52016-12-09 09:52:16 -05002428/* *INDENT-OFF* */
2429VLIB_REGISTER_NODE (ip6_rewrite_node) =
2430{
Neale Rannsf06aea52016-11-29 06:51:37 -08002431 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002432 .name = "ip6-rewrite",
2433 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002434 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002435 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002436 .next_nodes =
2437 {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002438 [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002439 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002440 },
2441};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002442/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002443
Neale Rannsf06aea52016-11-29 06:51:37 -08002444VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002445
Neale Ranns32e1c012016-11-22 17:07:28 +00002446/* *INDENT-OFF* */
2447VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2448{
2449 .function = ip6_rewrite_mcast,
2450 .name = "ip6-rewrite-mcast",
2451 .vector_size = sizeof (u32),
2452 .format_trace = format_ip6_rewrite_trace,
2453 .sibling_of = "ip6-rewrite",
2454};
2455/* *INDENT-ON* */
2456
2457VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2458
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002459/* *INDENT-OFF* */
2460VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2461{
2462 .function = ip6_mcast_midchain,
2463 .name = "ip6-mcast-midchain",
2464 .vector_size = sizeof (u32),
2465 .format_trace = format_ip6_rewrite_trace,
2466 .sibling_of = "ip6-rewrite",
2467};
2468/* *INDENT-ON* */
2469
2470VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2471
Ole Troan944f5482016-05-24 11:56:58 +02002472/*
2473 * Hop-by-Hop handling
2474 */
Ole Troan944f5482016-05-24 11:56:58 +02002475ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2476
2477#define foreach_ip6_hop_by_hop_error \
2478_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2479_(FORMAT, "incorrectly formatted hop-by-hop options") \
2480_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2481
Neale Ranns32e1c012016-11-22 17:07:28 +00002482/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002483typedef enum
2484{
Ole Troan944f5482016-05-24 11:56:58 +02002485#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2486 foreach_ip6_hop_by_hop_error
2487#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002488 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002489} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002490/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002491
2492/*
2493 * Primary h-b-h handler trace support
2494 * We work pretty hard on the problem for obvious reasons
2495 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002496typedef struct
2497{
Ole Troan944f5482016-05-24 11:56:58 +02002498 u32 next_index;
2499 u32 trace_len;
2500 u8 option_data[256];
2501} ip6_hop_by_hop_trace_t;
2502
2503vlib_node_registration_t ip6_hop_by_hop_node;
2504
Dave Barachd7cb1b52016-12-09 09:52:16 -05002505static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002506#define _(sym,string) string,
2507 foreach_ip6_hop_by_hop_error
2508#undef _
2509};
2510
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302511u8 *
2512format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2513{
2514 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2515 int total_len = va_arg (*args, int);
2516 ip6_hop_by_hop_option_t *opt0, *limit0;
2517 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2518 u8 type0;
2519
2520 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2521 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2522
2523 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2524 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2525
2526 while (opt0 < limit0)
2527 {
2528 type0 = opt0->type;
2529 switch (type0)
2530 {
2531 case 0: /* Pad, just stop */
2532 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2533 break;
2534
2535 default:
2536 if (hm->trace[type0])
2537 {
2538 s = (*hm->trace[type0]) (s, opt0);
2539 }
2540 else
2541 {
2542 s =
2543 format (s, "\n unrecognized option %d length %d", type0,
2544 opt0->length);
2545 }
2546 opt0 =
2547 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2548 sizeof (ip6_hop_by_hop_option_t));
2549 break;
2550 }
2551 }
2552 return s;
2553}
2554
Ole Troan944f5482016-05-24 11:56:58 +02002555static u8 *
2556format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2557{
2558 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2559 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002560 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002561 ip6_hop_by_hop_header_t *hbh0;
2562 ip6_hop_by_hop_option_t *opt0, *limit0;
2563 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2564
2565 u8 type0;
2566
Dave Barachd7cb1b52016-12-09 09:52:16 -05002567 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002568
2569 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002570 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002571
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2573 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002574
Dave Barachd7cb1b52016-12-09 09:52:16 -05002575 while (opt0 < limit0)
2576 {
2577 type0 = opt0->type;
2578 switch (type0)
2579 {
2580 case 0: /* Pad, just stop */
2581 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2582 break;
Ole Troan944f5482016-05-24 11:56:58 +02002583
Dave Barachd7cb1b52016-12-09 09:52:16 -05002584 default:
2585 if (hm->trace[type0])
2586 {
2587 s = (*hm->trace[type0]) (s, opt0);
2588 }
2589 else
2590 {
2591 s =
2592 format (s, "\n unrecognized option %d length %d", type0,
2593 opt0->length);
2594 }
2595 opt0 =
2596 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2597 sizeof (ip6_hop_by_hop_option_t));
2598 break;
2599 }
Ole Troan944f5482016-05-24 11:56:58 +02002600 }
Ole Troan944f5482016-05-24 11:56:58 +02002601 return s;
2602}
2603
Dave Barachd7cb1b52016-12-09 09:52:16 -05002604always_inline u8
2605ip6_scan_hbh_options (vlib_buffer_t * b0,
2606 ip6_header_t * ip0,
2607 ip6_hop_by_hop_header_t * hbh0,
2608 ip6_hop_by_hop_option_t * opt0,
2609 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002610{
2611 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2612 u8 type0;
2613 u8 error0 = 0;
2614
2615 while (opt0 < limit0)
2616 {
2617 type0 = opt0->type;
2618 switch (type0)
2619 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 case 0: /* Pad1 */
2621 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002622 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002623 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002624 break;
2625 default:
2626 if (hm->options[type0])
2627 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002628 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2629 {
Shwethaa91cbe62016-08-08 15:51:04 +01002630 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002631 return (error0);
2632 }
Shwethaa91cbe62016-08-08 15:51:04 +01002633 }
2634 else
2635 {
2636 /* Unrecognized mandatory option, check the two high order bits */
2637 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2638 {
2639 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2640 break;
2641 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2642 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2643 *next0 = IP_LOOKUP_NEXT_DROP;
2644 break;
2645 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2646 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2647 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002648 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2649 ICMP6_parameter_problem_unrecognized_option,
2650 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002651 break;
2652 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2653 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002654 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002655 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002656 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2657 icmp6_error_set_vnet_buffer (b0,
2658 ICMP6_parameter_problem,
2659 ICMP6_parameter_problem_unrecognized_option,
2660 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002661 }
2662 else
2663 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002664 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002665 }
2666 break;
2667 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002668 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002669 }
2670 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002671 opt0 =
2672 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2673 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002674 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002675 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002676}
2677
Ole Troan944f5482016-05-24 11:56:58 +02002678/*
2679 * Process the Hop-by-Hop Options header
2680 */
2681static uword
2682ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002683 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002684{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685 vlib_node_runtime_t *error_node =
2686 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002687 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2688 u32 n_left_from, *from, *to_next;
2689 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002690
2691 from = vlib_frame_vector_args (frame);
2692 n_left_from = frame->n_vectors;
2693 next_index = node->cached_next_index;
2694
Dave Barachd7cb1b52016-12-09 09:52:16 -05002695 while (n_left_from > 0)
2696 {
2697 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002698
Dave Barachd7cb1b52016-12-09 09:52:16 -05002699 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002700
Dave Barachd7cb1b52016-12-09 09:52:16 -05002701 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002702 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002703 u32 bi0, bi1;
2704 vlib_buffer_t *b0, *b1;
2705 u32 next0, next1;
2706 ip6_header_t *ip0, *ip1;
2707 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2708 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2709 u8 error0 = 0, error1 = 0;
2710
2711 /* Prefetch next iteration. */
2712 {
2713 vlib_buffer_t *p2, *p3;
2714
2715 p2 = vlib_get_buffer (vm, from[2]);
2716 p3 = vlib_get_buffer (vm, from[3]);
2717
2718 vlib_prefetch_buffer_header (p2, LOAD);
2719 vlib_prefetch_buffer_header (p3, LOAD);
2720
2721 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2722 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002723 }
2724
Dave Barachd7cb1b52016-12-09 09:52:16 -05002725 /* Speculatively enqueue b0, b1 to the current next frame */
2726 to_next[0] = bi0 = from[0];
2727 to_next[1] = bi1 = from[1];
2728 from += 2;
2729 to_next += 2;
2730 n_left_from -= 2;
2731 n_left_to_next -= 2;
2732
2733 b0 = vlib_get_buffer (vm, bi0);
2734 b1 = vlib_get_buffer (vm, bi1);
2735
2736 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2737 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002738 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002739 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002740 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002741
2742 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2743 next0 = adj0->lookup_next_index;
2744 next1 = adj1->lookup_next_index;
2745
2746 ip0 = vlib_buffer_get_current (b0);
2747 ip1 = vlib_buffer_get_current (b1);
2748 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2749 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2750 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2751 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2752 limit0 =
2753 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2754 ((hbh0->length + 1) << 3));
2755 limit1 =
2756 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2757 ((hbh1->length + 1) << 3));
2758
2759 /*
2760 * Basic validity checks
2761 */
2762 if ((hbh0->length + 1) << 3 >
2763 clib_net_to_host_u16 (ip0->payload_length))
2764 {
2765 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2766 next0 = IP_LOOKUP_NEXT_DROP;
2767 goto outdual;
2768 }
2769 /* Scan the set of h-b-h options, process ones that we understand */
2770 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2771
2772 if ((hbh1->length + 1) << 3 >
2773 clib_net_to_host_u16 (ip1->payload_length))
2774 {
2775 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2776 next1 = IP_LOOKUP_NEXT_DROP;
2777 goto outdual;
2778 }
2779 /* Scan the set of h-b-h options, process ones that we understand */
2780 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2781
2782 outdual:
2783 /* Has the classifier flagged this buffer for special treatment? */
2784 if (PREDICT_FALSE
2785 ((error0 == 0)
2786 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2787 next0 = hm->next_override;
2788
2789 /* Has the classifier flagged this buffer for special treatment? */
2790 if (PREDICT_FALSE
2791 ((error1 == 0)
2792 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2793 next1 = hm->next_override;
2794
2795 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2796 {
2797 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2798 {
2799 ip6_hop_by_hop_trace_t *t =
2800 vlib_add_trace (vm, node, b0, sizeof (*t));
2801 u32 trace_len = (hbh0->length + 1) << 3;
2802 t->next_index = next0;
2803 /* Capture the h-b-h option verbatim */
2804 trace_len =
2805 trace_len <
2806 ARRAY_LEN (t->option_data) ? trace_len :
2807 ARRAY_LEN (t->option_data);
2808 t->trace_len = trace_len;
2809 clib_memcpy (t->option_data, hbh0, trace_len);
2810 }
2811 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2812 {
2813 ip6_hop_by_hop_trace_t *t =
2814 vlib_add_trace (vm, node, b1, sizeof (*t));
2815 u32 trace_len = (hbh1->length + 1) << 3;
2816 t->next_index = next1;
2817 /* Capture the h-b-h option verbatim */
2818 trace_len =
2819 trace_len <
2820 ARRAY_LEN (t->option_data) ? trace_len :
2821 ARRAY_LEN (t->option_data);
2822 t->trace_len = trace_len;
2823 clib_memcpy (t->option_data, hbh1, trace_len);
2824 }
2825
2826 }
2827
2828 b0->error = error_node->errors[error0];
2829 b1->error = error_node->errors[error1];
2830
2831 /* verify speculative enqueue, maybe switch current next frame */
2832 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2833 n_left_to_next, bi0, bi1, next0,
2834 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002835 }
2836
Dave Barachd7cb1b52016-12-09 09:52:16 -05002837 while (n_left_from > 0 && n_left_to_next > 0)
2838 {
2839 u32 bi0;
2840 vlib_buffer_t *b0;
2841 u32 next0;
2842 ip6_header_t *ip0;
2843 ip6_hop_by_hop_header_t *hbh0;
2844 ip6_hop_by_hop_option_t *opt0, *limit0;
2845 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002846
Dave Barachd7cb1b52016-12-09 09:52:16 -05002847 /* Speculatively enqueue b0 to the current next frame */
2848 bi0 = from[0];
2849 to_next[0] = bi0;
2850 from += 1;
2851 to_next += 1;
2852 n_left_from -= 1;
2853 n_left_to_next -= 1;
2854
2855 b0 = vlib_get_buffer (vm, bi0);
2856 /*
2857 * Default use the next_index from the adjacency.
2858 * A HBH option rarely redirects to a different node
2859 */
2860 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002861 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002862 next0 = adj0->lookup_next_index;
2863
2864 ip0 = vlib_buffer_get_current (b0);
2865 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2866 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2867 limit0 =
2868 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2869 ((hbh0->length + 1) << 3));
2870
2871 /*
2872 * Basic validity checks
2873 */
2874 if ((hbh0->length + 1) << 3 >
2875 clib_net_to_host_u16 (ip0->payload_length))
2876 {
2877 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2878 next0 = IP_LOOKUP_NEXT_DROP;
2879 goto out0;
2880 }
2881
2882 /* Scan the set of h-b-h options, process ones that we understand */
2883 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2884
2885 out0:
2886 /* Has the classifier flagged this buffer for special treatment? */
2887 if (PREDICT_FALSE
2888 ((error0 == 0)
2889 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2890 next0 = hm->next_override;
2891
2892 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2893 {
2894 ip6_hop_by_hop_trace_t *t =
2895 vlib_add_trace (vm, node, b0, sizeof (*t));
2896 u32 trace_len = (hbh0->length + 1) << 3;
2897 t->next_index = next0;
2898 /* Capture the h-b-h option verbatim */
2899 trace_len =
2900 trace_len <
2901 ARRAY_LEN (t->option_data) ? trace_len :
2902 ARRAY_LEN (t->option_data);
2903 t->trace_len = trace_len;
2904 clib_memcpy (t->option_data, hbh0, trace_len);
2905 }
2906
2907 b0->error = error_node->errors[error0];
2908
2909 /* verify speculative enqueue, maybe switch current next frame */
2910 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2911 n_left_to_next, bi0, next0);
2912 }
2913 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002914 }
Ole Troan944f5482016-05-24 11:56:58 +02002915 return frame->n_vectors;
2916}
2917
Dave Barachd7cb1b52016-12-09 09:52:16 -05002918/* *INDENT-OFF* */
2919VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2920{
Ole Troan944f5482016-05-24 11:56:58 +02002921 .function = ip6_hop_by_hop,
2922 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002923 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002924 .vector_size = sizeof (u32),
2925 .format_trace = format_ip6_hop_by_hop_trace,
2926 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002927 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002928 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002929 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002930};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002931/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002932
Dave Barach5331c722016-08-17 11:54:30 -04002933VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002934
2935static clib_error_t *
2936ip6_hop_by_hop_init (vlib_main_t * vm)
2937{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002938 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2939 memset (hm->options, 0, sizeof (hm->options));
2940 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002941 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002942 return (0);
2943}
2944
2945VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2946
Dave Barachd7cb1b52016-12-09 09:52:16 -05002947void
2948ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002949{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002950 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002951
2952 hm->next_override = next;
2953}
2954
Ole Troan944f5482016-05-24 11:56:58 +02002955int
2956ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002957 int options (vlib_buffer_t * b, ip6_header_t * ip,
2958 ip6_hop_by_hop_option_t * opt),
2959 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002960{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002961 ip6_main_t *im = &ip6_main;
2962 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002963
2964 ASSERT (option < ARRAY_LEN (hm->options));
2965
2966 /* Already registered */
2967 if (hm->options[option])
2968 return (-1);
2969
2970 hm->options[option] = options;
2971 hm->trace[option] = trace;
2972
2973 /* Set global variable */
2974 im->hbh_enabled = 1;
2975
2976 return (0);
2977}
2978
2979int
2980ip6_hbh_unregister_option (u8 option)
2981{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002982 ip6_main_t *im = &ip6_main;
2983 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002984
2985 ASSERT (option < ARRAY_LEN (hm->options));
2986
2987 /* Not registered */
2988 if (!hm->options[option])
2989 return (-1);
2990
2991 hm->options[option] = NULL;
2992 hm->trace[option] = NULL;
2993
2994 /* Disable global knob if this was the last option configured */
2995 int i;
2996 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002997 for (i = 0; i < 256; i++)
2998 {
2999 if (hm->options[option])
3000 {
3001 found = true;
3002 break;
3003 }
Ole Troan944f5482016-05-24 11:56:58 +02003004 }
Ole Troan944f5482016-05-24 11:56:58 +02003005 if (!found)
3006 im->hbh_enabled = 0;
3007
3008 return (0);
3009}
3010
Ed Warnickecb9cada2015-12-08 15:45:58 -07003011/* Global IP6 main. */
3012ip6_main_t ip6_main;
3013
3014static clib_error_t *
3015ip6_lookup_init (vlib_main_t * vm)
3016{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003017 ip6_main_t *im = &ip6_main;
3018 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019 uword i;
3020
Damjan Marion8b3191e2016-11-09 19:54:20 +01003021 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
3022 return error;
3023
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
3025 {
3026 u32 j, i0, i1;
3027
3028 i0 = i / 32;
3029 i1 = i % 32;
3030
3031 for (j = 0; j < i0; j++)
3032 im->fib_masks[i].as_u32[j] = ~0;
3033
3034 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003035 im->fib_masks[i].as_u32[i0] =
3036 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003037 }
3038
3039 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
3040
3041 if (im->lookup_table_nbuckets == 0)
3042 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
3043
Dave Barachd7cb1b52016-12-09 09:52:16 -05003044 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045
3046 if (im->lookup_table_size == 0)
3047 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04003048
Dave Barachd7cb1b52016-12-09 09:52:16 -05003049 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
3050 "ip6 FIB fwding table",
3051 im->lookup_table_nbuckets, im->lookup_table_size);
3052 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
3053 "ip6 FIB non-fwding table",
3054 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003055
Ed Warnickecb9cada2015-12-08 15:45:58 -07003056 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07003057 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3058 FIB_SOURCE_DEFAULT_ROUTE);
3059 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3060 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061
3062 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003063 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003064 pn = pg_get_node (ip6_lookup_node.index);
3065 pn->unformat_edit = unformat_pg_ip6_header;
3066 }
3067
Ole Troan944f5482016-05-24 11:56:58 +02003068 /* Unless explicitly configured, don't process HBH options */
3069 im->hbh_enabled = 0;
3070
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071 {
3072 icmp6_neighbor_solicitation_header_t p;
3073
3074 memset (&p, 0, sizeof (p));
3075
Dave Barachd7cb1b52016-12-09 09:52:16 -05003076 p.ip.ip_version_traffic_class_and_flow_label =
3077 clib_host_to_net_u32 (0x6 << 28);
3078 p.ip.payload_length =
3079 clib_host_to_net_u16 (sizeof (p) -
3080 STRUCT_OFFSET_OF
3081 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003082 p.ip.protocol = IP_PROTOCOL_ICMP6;
3083 p.ip.hop_limit = 255;
3084 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3085
3086 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3087
Dave Barachd7cb1b52016-12-09 09:52:16 -05003088 p.link_layer_option.header.type =
3089 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3090 p.link_layer_option.header.n_data_u64s =
3091 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092
3093 vlib_packet_template_init (vm,
3094 &im->discover_neighbor_packet_template,
3095 &p, sizeof (p),
3096 /* alloc chunk size */ 8,
3097 "ip6 neighbor discovery");
3098 }
3099
Dave Barach203c6322016-06-26 10:29:03 -04003100 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003101}
3102
3103VLIB_INIT_FUNCTION (ip6_lookup_init);
3104
Dave Barach75fc8542016-10-11 16:16:02 -04003105void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003106ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3107 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108{
3109 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3110 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003111 ip->as_u8[8] = mac[0] ^ (1 << 1);
3112 ip->as_u8[9] = mac[1];
3113 ip->as_u8[10] = mac[2];
3114 ip->as_u8[11] = 0xFF;
3115 ip->as_u8[12] = 0xFE;
3116 ip->as_u8[13] = mac[3];
3117 ip->as_u8[14] = mac[4];
3118 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003119}
3120
Dave Barach75fc8542016-10-11 16:16:02 -04003121void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003122ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3123 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003124{
3125 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003126 mac[0] = ip->as_u8[8] ^ (1 << 1);
3127 mac[1] = ip->as_u8[9];
3128 mac[2] = ip->as_u8[10];
3129 mac[3] = ip->as_u8[13];
3130 mac[4] = ip->as_u8[14];
3131 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132}
3133
Dave Barach75fc8542016-10-11 16:16:02 -04003134static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003136 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003137{
3138 u8 mac[6];
3139 ip6_address_t _a, *a = &_a;
3140
3141 if (unformat (input, "%U", unformat_ethernet_address, mac))
3142 {
3143 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003144 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003145 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3146 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003147 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003148 }
Dave Barach75fc8542016-10-11 16:16:02 -04003149
Ed Warnickecb9cada2015-12-08 15:45:58 -07003150 return 0;
3151}
3152
Billy McFall0683c9c2016-10-13 08:27:31 -04003153/*?
3154 * This command converts the given MAC Address into an IPv6 link-local
3155 * address.
3156 *
3157 * @cliexpar
3158 * Example of how to create an IPv6 link-local address:
3159 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3160 * Link local address: fe80::14d9:e0ff:fe91:7986
3161 * Original MAC address: 16:d9:e0:91:79:86
3162 * @cliexend
3163?*/
3164/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003165VLIB_CLI_COMMAND (test_link_command, static) =
3166{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003168 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003169 .short_help = "test ip6 link <mac-address>",
3170};
Billy McFall0683c9c2016-10-13 08:27:31 -04003171/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172
Dave Barachd7cb1b52016-12-09 09:52:16 -05003173int
3174vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175{
Neale Ranns107e7d42017-04-11 09:55:19 -07003176 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003177
Neale Ranns107e7d42017-04-11 09:55:19 -07003178 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003179
Neale Ranns107e7d42017-04-11 09:55:19 -07003180 if (~0 == fib_index)
3181 return VNET_API_ERROR_NO_SUCH_FIB;
3182
Neale Ranns227038a2017-04-21 01:07:59 -07003183 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3184 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003185
Neale Ranns227038a2017-04-21 01:07:59 -07003186 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003187}
3188
3189static clib_error_t *
3190set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003191 unformat_input_t * input,
3192 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003193{
3194 int matched = 0;
3195 u32 table_id = 0;
3196 u32 flow_hash_config = 0;
3197 int rv;
3198
Dave Barachd7cb1b52016-12-09 09:52:16 -05003199 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3200 {
3201 if (unformat (input, "table %d", &table_id))
3202 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203#define _(a,v) \
3204 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003205 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003206#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003207 else
3208 break;
3209 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003210
3211 if (matched == 0)
3212 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003213 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003214
Ed Warnickecb9cada2015-12-08 15:45:58 -07003215 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3216 switch (rv)
3217 {
Neale Ranns227038a2017-04-21 01:07:59 -07003218 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003219 break;
3220
3221 case -1:
3222 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003223
Ed Warnickecb9cada2015-12-08 15:45:58 -07003224 default:
3225 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3226 break;
3227 }
Dave Barach75fc8542016-10-11 16:16:02 -04003228
Ed Warnickecb9cada2015-12-08 15:45:58 -07003229 return 0;
3230}
3231
Billy McFall0683c9c2016-10-13 08:27:31 -04003232/*?
3233 * Configure the set of IPv6 fields used by the flow hash.
3234 *
3235 * @cliexpar
3236 * @parblock
3237 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003238 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3239 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003240 * Example of display the configured flow hash:
3241 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003242 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3243 * @::/0
3244 * unicast-ip6-chain
3245 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3246 * [0] [@0]: dpo-drop ip6
3247 * fe80::/10
3248 * unicast-ip6-chain
3249 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3250 * [0] [@2]: dpo-receive
3251 * ff02::1/128
3252 * unicast-ip6-chain
3253 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3254 * [0] [@2]: dpo-receive
3255 * ff02::2/128
3256 * unicast-ip6-chain
3257 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3258 * [0] [@2]: dpo-receive
3259 * ff02::16/128
3260 * unicast-ip6-chain
3261 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3262 * [0] [@2]: dpo-receive
3263 * ff02::1:ff00:0/104
3264 * unicast-ip6-chain
3265 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3266 * [0] [@2]: dpo-receive
3267 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3268 * @::/0
3269 * unicast-ip6-chain
3270 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3271 * [0] [@0]: dpo-drop ip6
3272 * @::a:1:1:0:4/126
3273 * unicast-ip6-chain
3274 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3275 * [0] [@4]: ipv6-glean: af_packet0
3276 * @::a:1:1:0:7/128
3277 * unicast-ip6-chain
3278 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3279 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3280 * fe80::/10
3281 * unicast-ip6-chain
3282 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3283 * [0] [@2]: dpo-receive
3284 * fe80::fe:3eff:fe3e:9222/128
3285 * unicast-ip6-chain
3286 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3287 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3288 * ff02::1/128
3289 * unicast-ip6-chain
3290 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3291 * [0] [@2]: dpo-receive
3292 * ff02::2/128
3293 * unicast-ip6-chain
3294 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3295 * [0] [@2]: dpo-receive
3296 * ff02::16/128
3297 * unicast-ip6-chain
3298 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3299 * [0] [@2]: dpo-receive
3300 * ff02::1:ff00:0/104
3301 * unicast-ip6-chain
3302 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3303 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003304 * @cliexend
3305 * @endparblock
3306?*/
3307/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003308VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3309{
3310 .path = "set ip6 flow-hash",
3311 .short_help =
3312 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3313 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003314};
Billy McFall0683c9c2016-10-13 08:27:31 -04003315/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003316
3317static clib_error_t *
3318show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003319 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003320{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003321 ip6_main_t *im = &ip6_main;
3322 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003323 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003324
Ed Warnickecb9cada2015-12-08 15:45:58 -07003325 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003326 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003327 {
3328 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02003329 {
3330
3331 u32 node_index = vlib_get_node (vm,
3332 ip6_local_node.index)->
3333 next_nodes[lm->local_next_by_ip_protocol[i]];
3334 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3335 node_index);
3336 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003337 }
3338 return 0;
3339}
3340
3341
3342
Billy McFall0683c9c2016-10-13 08:27:31 -04003343/*?
3344 * Display the set of protocols handled by the local IPv6 stack.
3345 *
3346 * @cliexpar
3347 * Example of how to display local protocol table:
3348 * @cliexstart{show ip6 local}
3349 * Protocols handled by ip6_local
3350 * 17
3351 * 43
3352 * 58
3353 * 115
3354 * @cliexend
3355?*/
3356/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003357VLIB_CLI_COMMAND (show_ip6_local, static) =
3358{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003359 .path = "show ip6 local",
3360 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003361 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003362};
Billy McFall0683c9c2016-10-13 08:27:31 -04003363/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003364
Dave Barachd7cb1b52016-12-09 09:52:16 -05003365int
3366vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3367 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003368{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003369 vnet_main_t *vnm = vnet_get_main ();
3370 vnet_interface_main_t *im = &vnm->interface_main;
3371 ip6_main_t *ipm = &ip6_main;
3372 ip_lookup_main_t *lm = &ipm->lookup_main;
3373 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003374 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003375
3376 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3377 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3378
3379 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3380 return VNET_API_ERROR_NO_SUCH_ENTRY;
3381
3382 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003383 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003384
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003385 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003386
3387 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003388 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003389 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003390 .fp_len = 128,
3391 .fp_proto = FIB_PROTOCOL_IP6,
3392 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003393 };
3394 u32 fib_index;
3395
Dave Barachd7cb1b52016-12-09 09:52:16 -05003396 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3397 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003398
3399
Dave Barachd7cb1b52016-12-09 09:52:16 -05003400 if (table_index != (u32) ~ 0)
3401 {
3402 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003403
Dave Barachd7cb1b52016-12-09 09:52:16 -05003404 dpo_set (&dpo,
3405 DPO_CLASSIFY,
3406 DPO_PROTO_IP6,
3407 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003408
Dave Barachd7cb1b52016-12-09 09:52:16 -05003409 fib_table_entry_special_dpo_add (fib_index,
3410 &pfx,
3411 FIB_SOURCE_CLASSIFY,
3412 FIB_ENTRY_FLAG_NONE, &dpo);
3413 dpo_reset (&dpo);
3414 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003415 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003416 {
3417 fib_table_entry_special_remove (fib_index,
3418 &pfx, FIB_SOURCE_CLASSIFY);
3419 }
3420 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003421
Ed Warnickecb9cada2015-12-08 15:45:58 -07003422 return 0;
3423}
3424
3425static clib_error_t *
3426set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003427 unformat_input_t * input,
3428 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003429{
3430 u32 table_index = ~0;
3431 int table_index_set = 0;
3432 u32 sw_if_index = ~0;
3433 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003434
Dave Barachd7cb1b52016-12-09 09:52:16 -05003435 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3436 {
3437 if (unformat (input, "table-index %d", &table_index))
3438 table_index_set = 1;
3439 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3440 vnet_get_main (), &sw_if_index))
3441 ;
3442 else
3443 break;
3444 }
Dave Barach75fc8542016-10-11 16:16:02 -04003445
Ed Warnickecb9cada2015-12-08 15:45:58 -07003446 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003447 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003448
Ed Warnickecb9cada2015-12-08 15:45:58 -07003449 if (sw_if_index == ~0)
3450 return clib_error_return (0, "interface / subif must be specified");
3451
3452 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3453
3454 switch (rv)
3455 {
3456 case 0:
3457 break;
3458
3459 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3460 return clib_error_return (0, "No such interface");
3461
3462 case VNET_API_ERROR_NO_SUCH_ENTRY:
3463 return clib_error_return (0, "No such classifier table");
3464 }
3465 return 0;
3466}
3467
Billy McFall0683c9c2016-10-13 08:27:31 -04003468/*?
3469 * Assign a classification table to an interface. The classification
3470 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3471 * commands. Once the table is create, use this command to filter packets
3472 * on an interface.
3473 *
3474 * @cliexpar
3475 * Example of how to assign a classification table to an interface:
3476 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3477?*/
3478/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003479VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3480{
3481 .path = "set ip6 classify",
3482 .short_help =
3483 "set ip6 classify intfc <interface> table-index <classify-idx>",
3484 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003485};
Billy McFall0683c9c2016-10-13 08:27:31 -04003486/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003487
3488static clib_error_t *
3489ip6_config (vlib_main_t * vm, unformat_input_t * input)
3490{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003491 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003492 uword heapsize = 0;
3493 u32 tmp;
3494 u32 nbuckets = 0;
3495
Dave Barachd7cb1b52016-12-09 09:52:16 -05003496 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3497 {
3498 if (unformat (input, "hash-buckets %d", &tmp))
3499 nbuckets = tmp;
Neale Ranns1ec36522017-11-29 05:20:37 -08003500 else if (unformat (input, "heap-size %U",
3501 unformat_memory_size, &heapsize))
3502 ;
Dave Barachd7cb1b52016-12-09 09:52:16 -05003503 else
3504 return clib_error_return (0, "unknown input '%U'",
3505 format_unformat_error, input);
3506 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003507
3508 im->lookup_table_nbuckets = nbuckets;
3509 im->lookup_table_size = heapsize;
3510
3511 return 0;
3512}
3513
3514VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003515
3516/*
3517 * fd.io coding-style-patch-verification: ON
3518 *
3519 * Local Variables:
3520 * eval: (c-set-style "gnu")
3521 * End:
3522 */