blob: a14bf09742b2add369f9252184217d613fed7a53 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
AkshayaNadahallied4a2fd2016-08-09 13:38:04 +05302 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip6_forward.c: IP v6 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +020042#include <vnet/ip/ip6_neighbor.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070044#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
45#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053046#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000048#include <vnet/mfib/ip6_mfib.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070049#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010050#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/bihash_template.c>
53
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053054/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
55#define OI_DECAP 0x80000000
56
Billy McFall0683c9c2016-10-13 08:27:31 -040057/**
58 * @file
59 * @brief IPv6 Forwarding.
60 *
61 * This file contains the source code for IPv6 forwarding.
62 */
63
Pierre Pfister0febaf12016-06-08 12:23:21 +010064
Damjan Marionaca64c92016-04-13 09:48:56 +020065always_inline uword
66ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050067 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barachd7cb1b52016-12-09 09:52:16 -050069 ip6_main_t *im = &ip6_main;
70 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
71 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +020073 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070074
75 from = vlib_frame_vector_args (frame);
76 n_left_from = frame->n_vectors;
77 next = node->cached_next_index;
78
79 while (n_left_from > 0)
80 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050081 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
83 while (n_left_from >= 4 && n_left_to_next >= 2)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010086 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050088 ip6_header_t *ip0, *ip1;
89 ip6_address_t *dst_addr0, *dst_addr1;
90 u32 fib_index0, fib_index1;
91 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010092 const dpo_id_t *dpo0, *dpo1;
93 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
95 /* Prefetch next iteration. */
96 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050097 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 p2 = vlib_get_buffer (vm, from[2]);
100 p3 = vlib_get_buffer (vm, from[3]);
101
102 vlib_prefetch_buffer_header (p2, LOAD);
103 vlib_prefetch_buffer_header (p3, LOAD);
104 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
105 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
106 }
107
108 pi0 = to_next[0] = from[0];
109 pi1 = to_next[1] = from[1];
110
111 p0 = vlib_get_buffer (vm, pi0);
112 p1 = vlib_get_buffer (vm, pi1);
113
114 ip0 = vlib_buffer_get_current (p0);
115 ip1 = vlib_buffer_get_current (p1);
116
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100117 dst_addr0 = &ip0->dst_address;
118 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200119
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 fib_index0 =
121 vec_elt (im->fib_index_by_sw_if_index,
122 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
123 fib_index1 =
124 vec_elt (im->fib_index_by_sw_if_index,
125 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
128 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
129 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
130 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
133 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100135 lb0 = load_balance_get (lbi0);
136 lb1 = load_balance_get (lbi1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700137 ASSERT (lb0->lb_n_buckets > 0);
138 ASSERT (lb1->lb_n_buckets > 0);
139 ASSERT (is_pow2 (lb0->lb_n_buckets));
140 ASSERT (is_pow2 (lb1->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700141
Dave Barachd7cb1b52016-12-09 09:52:16 -0500142 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
Dave Barachd7cb1b52016-12-09 09:52:16 -0500144 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
145 {
146 flow_hash_config0 = lb0->lb_hash_config;
147 vnet_buffer (p0)->ip.flow_hash =
148 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700149 dpo0 =
150 load_balance_get_fwd_bucket (lb0,
151 (vnet_buffer (p0)->ip.flow_hash &
152 (lb0->lb_n_buckets_minus_1)));
153 }
154 else
155 {
156 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500157 }
158 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
159 {
160 flow_hash_config1 = lb1->lb_hash_config;
161 vnet_buffer (p1)->ip.flow_hash =
162 ip6_compute_flow_hash (ip1, flow_hash_config1);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700163 dpo1 =
164 load_balance_get_fwd_bucket (lb1,
165 (vnet_buffer (p1)->ip.flow_hash &
166 (lb1->lb_n_buckets_minus_1)));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500167 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700168 else
169 {
170 dpo1 = load_balance_get_bucket_i (lb1, 0);
171 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100172 next0 = dpo0->dpoi_next_node;
173 next1 = dpo1->dpoi_next_node;
174
175 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500176 if (PREDICT_FALSE
177 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100178 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500179 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100180 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
181 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 if (PREDICT_FALSE
183 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100184 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500185 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100186 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
187 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100188 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
189 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barach75fc8542016-10-11 16:16:02 -0400191 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200192 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400193 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200194 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
196 from += 2;
197 to_next += 2;
198 n_left_to_next -= 2;
199 n_left_from -= 2;
200
Dave Barachd7cb1b52016-12-09 09:52:16 -0500201 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500203 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 switch (wrong_next)
205 {
206 case 1:
207 /* A B A */
208 to_next[-2] = pi1;
209 to_next -= 1;
210 n_left_to_next += 1;
211 vlib_set_next_frame_buffer (vm, node, next0, pi0);
212 break;
213
214 case 2:
215 /* A A B */
216 to_next -= 1;
217 n_left_to_next += 1;
218 vlib_set_next_frame_buffer (vm, node, next1, pi1);
219 break;
220
221 case 3:
222 /* A B C */
223 to_next -= 2;
224 n_left_to_next += 2;
225 vlib_set_next_frame_buffer (vm, node, next0, pi0);
226 vlib_set_next_frame_buffer (vm, node, next1, pi1);
227 if (next0 == next1)
228 {
229 /* A B B */
230 vlib_put_next_frame (vm, node, next, n_left_to_next);
231 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500232 vlib_get_next_frame (vm, node, next, to_next,
233 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 }
235 }
236 }
237 }
Dave Barach75fc8542016-10-11 16:16:02 -0400238
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 while (n_left_from > 0 && n_left_to_next > 0)
240 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500241 vlib_buffer_t *p0;
242 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100243 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500245 load_balance_t *lb0;
246 ip6_address_t *dst_addr0;
247 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249
250 pi0 = from[0];
251 to_next[0] = pi0;
252
253 p0 = vlib_get_buffer (vm, pi0);
254
255 ip0 = vlib_buffer_get_current (p0);
256
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100257 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200258
Dave Barachd7cb1b52016-12-09 09:52:16 -0500259 fib_index0 =
260 vec_elt (im->fib_index_by_sw_if_index,
261 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
262 fib_index0 =
263 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
264 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100266 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100268 lb0 = load_balance_get (lbi0);
Neale Ranns227038a2017-04-21 01:07:59 -0700269 flow_hash_config0 = lb0->lb_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270
Dave Barachd7cb1b52016-12-09 09:52:16 -0500271 vnet_buffer (p0)->ip.flow_hash = 0;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700272 ASSERT (lb0->lb_n_buckets > 0);
273 ASSERT (is_pow2 (lb0->lb_n_buckets));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274
Dave Barachd7cb1b52016-12-09 09:52:16 -0500275 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
276 {
277 flow_hash_config0 = lb0->lb_hash_config;
278 vnet_buffer (p0)->ip.flow_hash =
279 ip6_compute_flow_hash (ip0, flow_hash_config0);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700280 dpo0 =
281 load_balance_get_fwd_bucket (lb0,
282 (vnet_buffer (p0)->ip.flow_hash &
283 (lb0->lb_n_buckets_minus_1)));
284 }
285 else
286 {
287 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500288 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
Dave Barachd7cb1b52016-12-09 09:52:16 -0500290 dpo0 = load_balance_get_bucket_i (lb0,
291 (vnet_buffer (p0)->ip.flow_hash &
292 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100293 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
Shwetha57fc8542016-09-27 08:04:05 +0100295 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500296 if (PREDICT_FALSE
297 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100298 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500299 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100300 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
301 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100302 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303
Dave Barach75fc8542016-10-11 16:16:02 -0400304 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200305 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
307 from += 1;
308 to_next += 1;
309 n_left_to_next -= 1;
310 n_left_from -= 1;
311
312 if (PREDICT_FALSE (next0 != next))
313 {
314 n_left_to_next += 1;
315 vlib_put_next_frame (vm, node, next, n_left_to_next);
316 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 to_next[0] = pi0;
319 to_next += 1;
320 n_left_to_next -= 1;
321 }
322 }
323
324 vlib_put_next_frame (vm, node, next, n_left_to_next);
325 }
326
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100327 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500328 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100329
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 return frame->n_vectors;
331}
332
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333static void
334ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
335 ip6_main_t * im, u32 fib_index,
336 ip_interface_address_t * a)
337{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500338 ip_lookup_main_t *lm = &im->lookup_main;
339 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100340 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500341 .fp_len = a->address_length,
342 .fp_proto = FIB_PROTOCOL_IP6,
343 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100344 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 {
Neale Ranns7a272742017-05-30 02:08:14 -0700348 fib_table_entry_update_one_path (fib_index,
349 &pfx,
350 FIB_SOURCE_INTERFACE,
351 (FIB_ENTRY_FLAG_CONNECTED |
352 FIB_ENTRY_FLAG_ATTACHED),
Neale Rannsda78f952017-05-24 09:15:43 -0700353 DPO_PROTO_IP6,
Neale Ranns7a272742017-05-30 02:08:14 -0700354 /* No next-hop address */
355 NULL, sw_if_index,
356 /* invalid FIB index */
357 ~0, 1,
358 /* no label stack */
359 NULL, FIB_ROUTE_PATH_FLAG_NONE);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500360 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100362 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500364 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100365 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500366 lm->classify_table_index_by_sw_if_index[sw_if_index];
367 if (classify_table_index != (u32) ~ 0)
368 {
369 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370
Dave Barachd7cb1b52016-12-09 09:52:16 -0500371 dpo_set (&dpo,
372 DPO_CLASSIFY,
373 DPO_PROTO_IP6,
374 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100375
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 fib_table_entry_special_dpo_add (fib_index,
377 &pfx,
378 FIB_SOURCE_CLASSIFY,
379 FIB_ENTRY_FLAG_NONE, &dpo);
380 dpo_reset (&dpo);
381 }
382 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100383
Neale Rannsf12a83f2017-04-18 09:09:40 -0700384 fib_table_entry_update_one_path (fib_index, &pfx,
385 FIB_SOURCE_INTERFACE,
386 (FIB_ENTRY_FLAG_CONNECTED |
387 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700388 DPO_PROTO_IP6,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700389 &pfx.fp_addr,
390 sw_if_index, ~0,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500391 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392}
393
394static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100395ip6_del_interface_routes (ip6_main_t * im,
396 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500397 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500399 fib_prefix_t pfx = {
400 .fp_len = address_length,
401 .fp_proto = FIB_PROTOCOL_IP6,
402 .fp_addr.ip6 = *address,
403 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404
Dave Barachd7cb1b52016-12-09 09:52:16 -0500405 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500407 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100408
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 }
410
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 pfx.fp_len = 128;
412 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413}
414
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100415void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500416ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100417{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500418 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100420 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422 /*
423 * enable/disable only on the 1<->0 transition
424 */
425 if (is_enable)
426 {
427 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500428 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100429 }
430 else
431 {
Neale Ranns75152282017-01-09 01:00:45 -0800432 /* The ref count is 0 when an address is removed from an interface that has
433 * no address - this is not a ciritical error */
434 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
435 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500436 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100437 }
438
Neale Ranns630198f2017-05-22 09:20:20 -0400439 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
440 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100441
Neale Ranns630198f2017-05-22 09:20:20 -0400442 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
443 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444}
445
Neale Rannsdf089a82016-10-02 16:39:06 +0100446/* get first interface address */
447ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800448ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100449{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500450 ip_lookup_main_t *lm = &im->lookup_main;
451 ip_interface_address_t *ia = 0;
452 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100453
Dave Barachd7cb1b52016-12-09 09:52:16 -0500454 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100455 foreach_ip_interface_address (lm, ia, sw_if_index,
456 1 /* honor unnumbered */,
457 ({
458 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
459 result = a;
460 break;
461 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100463 return result;
464}
465
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466clib_error_t *
467ip6_add_del_interface_address (vlib_main_t * vm,
468 u32 sw_if_index,
469 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500470 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 vnet_main_t *vnm = vnet_get_main ();
473 ip6_main_t *im = &ip6_main;
474 ip_lookup_main_t *lm = &im->lookup_main;
475 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500477 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478
Pavel Kotucek57808982017-08-02 08:20:19 +0200479 /* local0 interface doesn't support IP addressing */
480 if (sw_if_index == 0)
481 {
482 return
483 clib_error_create ("local0 interface doesn't support IP addressing");
484 }
485
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000487 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
488
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489 ip6_addr_fib_init (&ip6_af, address,
490 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
491 vec_add1 (addr_fib, ip6_af);
492
493 {
494 uword elts_before = pool_elts (lm->if_address_pool);
495
496 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500497 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 if (error)
499 goto done;
500
501 /* Pool did not grow: add duplicate address. */
502 if (elts_before == pool_elts (lm->if_address_pool))
503 goto done;
504 }
505
Dave Barachd7cb1b52016-12-09 09:52:16 -0500506 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000507
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100508 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500509 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100510 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500511 ip6_add_interface_routes (vnm, sw_if_index,
512 im, ip6_af.fib_index,
513 pool_elt_at_index (lm->if_address_pool,
514 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500517 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518 vec_foreach (cb, im->add_del_interface_address_callbacks)
519 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 }
522
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 vec_free (addr_fib);
525 return error;
526}
527
528clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500529ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500531 ip6_main_t *im = &ip6_main;
532 ip_interface_address_t *ia;
533 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 u32 is_admin_up, fib_index;
535
536 /* Fill in lookup tables with default table (0). */
537 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
538
Dave Barachd7cb1b52016-12-09 09:52:16 -0500539 vec_validate_init_empty (im->
540 lookup_main.if_address_pool_index_by_sw_if_index,
541 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542
543 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
544
545 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
546
Dave Barachd7cb1b52016-12-09 09:52:16 -0500547 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400548 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 0 /* honor unnumbered */,
550 ({
551 a = ip_interface_address_get_address (&im->lookup_main, ia);
552 if (is_admin_up)
553 ip6_add_interface_routes (vnm, sw_if_index,
554 im, fib_index,
555 ia);
556 else
557 ip6_del_interface_routes (im, fib_index,
558 a, ia->address_length);
559 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500560 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561
562 return 0;
563}
564
565VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
566
Dave Barachd6534602016-06-14 18:38:02 -0400567/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500568/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100569VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
570{
571 .arc_name = "ip6-unicast",
572 .start_nodes = VNET_FEATURES ("ip6-input"),
573 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
574};
575
Dave Barachd7cb1b52016-12-09 09:52:16 -0500576VNET_FEATURE_INIT (ip6_flow_classify, static) =
577{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100578 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700579 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100580 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700581};
582
Dave Barachd7cb1b52016-12-09 09:52:16 -0500583VNET_FEATURE_INIT (ip6_inacl, static) =
584{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100585 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400586 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100587 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400588};
589
Dave Barachd7cb1b52016-12-09 09:52:16 -0500590VNET_FEATURE_INIT (ip6_policer_classify, static) =
591{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100592 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700593 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100594 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700595};
596
Dave Barachd7cb1b52016-12-09 09:52:16 -0500597VNET_FEATURE_INIT (ip6_ipsec, static) =
598{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100599 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400600 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100601 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400602};
603
Dave Barachd7cb1b52016-12-09 09:52:16 -0500604VNET_FEATURE_INIT (ip6_l2tp, static) =
605{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100606 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400607 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100608 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400609};
610
Dave Barachd7cb1b52016-12-09 09:52:16 -0500611VNET_FEATURE_INIT (ip6_vpath, static) =
612{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100613 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400614 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500615 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
616};
617
618VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
619{
620 .arc_name = "ip6-unicast",
621 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100622 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400623};
624
Dave Barachd7cb1b52016-12-09 09:52:16 -0500625VNET_FEATURE_INIT (ip6_drop, static) =
626{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100627 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100628 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400629 .runs_before = VNET_FEATURES ("ip6-lookup"),
630};
631
632VNET_FEATURE_INIT (ip6_lookup, static) =
633{
634 .arc_name = "ip6-unicast",
635 .node_name = "ip6-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637};
638
Dave Barachd6534602016-06-14 18:38:02 -0400639/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100640VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
641{
642 .arc_name = "ip6-multicast",
643 .start_nodes = VNET_FEATURES ("ip6-input"),
644 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
645};
646
647VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
648 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400649 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000650 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400651};
652
Damjan Marion8b3191e2016-11-09 19:54:20 +0100653VNET_FEATURE_INIT (ip6_drop_mc, static) = {
654 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100655 .node_name = "ip6-drop",
Neale Ranns630198f2017-05-22 09:20:20 -0400656 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
657};
658
659VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
660 .arc_name = "ip6-multicast",
661 .node_name = "ip6-mfib-forward-lookup",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100663};
Dave Barach5331c722016-08-17 11:54:30 -0400664
665/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100666VNET_FEATURE_ARC_INIT (ip6_output, static) =
667{
668 .arc_name = "ip6-output",
669 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
670 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400671};
672
Matus Fabian08a6f012016-11-15 06:08:51 -0800673VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
674 .arc_name = "ip6-output",
675 .node_name = "ipsec-output-ip6",
676 .runs_before = VNET_FEATURES ("interface-output"),
677};
678
Damjan Marion8b3191e2016-11-09 19:54:20 +0100679VNET_FEATURE_INIT (ip6_interface_output, static) = {
680 .arc_name = "ip6-output",
681 .node_name = "interface-output",
682 .runs_before = 0, /* not before any other features */
683};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500684/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400685
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500687ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688{
Florin Corasb5c13fd2017-05-10 12:32:53 -0700689 ip6_main_t *im = &ip6_main;
690
691 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
692 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
693
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +0200694 if (!is_add)
695 {
696 /* Ensure that IPv6 is disabled */
697 ip6_main_t *im6 = &ip6_main;
698 ip_lookup_main_t *lm6 = &im6->lookup_main;
699 ip_interface_address_t *ia = 0;
700 ip6_address_t *address;
701 vlib_main_t *vm = vlib_get_main ();
702
703 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
704 /* *INDENT-OFF* */
705 foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* honor unnumbered */,
706 ({
707 address = ip_interface_address_get_address (lm6, ia);
708 ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
709 }));
710 /* *INDENT-ON* */
711 ip6_mfib_interface_enable_disable (sw_if_index, 0);
712 }
713
Damjan Marion8b3191e2016-11-09 19:54:20 +0100714 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
715 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Damjan Marion8b3191e2016-11-09 19:54:20 +0100717 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
718 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720 return /* no error */ 0;
721}
722
723VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
724
Damjan Marionaca64c92016-04-13 09:48:56 +0200725static uword
726ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500727 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200728{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100729 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200730}
731
Dave Barachd7cb1b52016-12-09 09:52:16 -0500732static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100733
Dave Barachd7cb1b52016-12-09 09:52:16 -0500734/* *INDENT-OFF* */
735VLIB_REGISTER_NODE (ip6_lookup_node) =
736{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 .function = ip6_lookup,
738 .name = "ip6-lookup",
739 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100740 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200741 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200742 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
Dave Barachd7cb1b52016-12-09 09:52:16 -0500746VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200747
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100748always_inline uword
749ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200751{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500752 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
753 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100754 ip_lookup_next_t next;
Damjan Marion586afd72017-04-05 19:18:20 +0200755 u32 thread_index = vlib_get_thread_index ();
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100757
758 from = vlib_frame_vector_args (frame);
759 n_left_from = frame->n_vectors;
760 next = node->cached_next_index;
761
762 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764
765 while (n_left_from > 0)
766 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500767 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100768
Dave Barach75fc8542016-10-11 16:16:02 -0400769
Neale Ranns2be95c12016-11-19 13:50:04 +0000770 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500771 {
772 ip_lookup_next_t next0, next1;
773 const load_balance_t *lb0, *lb1;
774 vlib_buffer_t *p0, *p1;
775 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
776 const ip6_header_t *ip0, *ip1;
777 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000778
Dave Barachd7cb1b52016-12-09 09:52:16 -0500779 /* Prefetch next iteration. */
780 {
781 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000782
Dave Barachd7cb1b52016-12-09 09:52:16 -0500783 p2 = vlib_get_buffer (vm, from[2]);
784 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000785
Dave Barachd7cb1b52016-12-09 09:52:16 -0500786 vlib_prefetch_buffer_header (p2, STORE);
787 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000788
Dave Barachd7cb1b52016-12-09 09:52:16 -0500789 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
790 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
791 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000792
Dave Barachd7cb1b52016-12-09 09:52:16 -0500793 pi0 = to_next[0] = from[0];
794 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000795
Dave Barachd7cb1b52016-12-09 09:52:16 -0500796 from += 2;
797 n_left_from -= 2;
798 to_next += 2;
799 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000800
Dave Barachd7cb1b52016-12-09 09:52:16 -0500801 p0 = vlib_get_buffer (vm, pi0);
802 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000803
Dave Barachd7cb1b52016-12-09 09:52:16 -0500804 ip0 = vlib_buffer_get_current (p0);
805 ip1 = vlib_buffer_get_current (p1);
806 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
807 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000808
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 lb0 = load_balance_get (lbi0);
810 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000811
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 /*
813 * this node is for via FIBs we can re-use the hash value from the
814 * to node if present.
815 * We don't want to use the same hash value at each level in the recursion
816 * graph as that would lead to polarisation
817 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000818 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000819
Dave Barachd7cb1b52016-12-09 09:52:16 -0500820 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
821 {
822 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
823 {
824 hc0 = vnet_buffer (p0)->ip.flow_hash =
825 vnet_buffer (p0)->ip.flow_hash >> 1;
826 }
827 else
828 {
829 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000830 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500831 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700832 dpo0 =
833 load_balance_get_fwd_bucket (lb0,
834 (hc0 &
835 lb0->lb_n_buckets_minus_1));
836 }
837 else
838 {
839 dpo0 = load_balance_get_bucket_i (lb0, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500840 }
841 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
842 {
843 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
844 {
845 hc1 = vnet_buffer (p1)->ip.flow_hash =
846 vnet_buffer (p1)->ip.flow_hash >> 1;
847 }
848 else
849 {
850 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000851 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500852 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700853 dpo1 =
854 load_balance_get_fwd_bucket (lb1,
855 (hc1 &
856 lb1->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700858 else
859 {
860 dpo1 = load_balance_get_bucket_i (lb1, 0);
861 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000862
Dave Barachd7cb1b52016-12-09 09:52:16 -0500863 next0 = dpo0->dpoi_next_node;
864 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000865
Dave Barachd7cb1b52016-12-09 09:52:16 -0500866 /* Only process the HBH Option Header if explicitly configured to do so */
867 if (PREDICT_FALSE
868 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
869 {
870 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
871 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
872 }
873 /* Only process the HBH Option Header if explicitly configured to do so */
874 if (PREDICT_FALSE
875 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
876 {
877 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
878 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
879 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000880
Dave Barachd7cb1b52016-12-09 09:52:16 -0500881 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
882 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000883
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200885 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500886 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200887 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000888
Dave Barachd7cb1b52016-12-09 09:52:16 -0500889 vlib_validate_buffer_enqueue_x2 (vm, node, next,
890 to_next, n_left_to_next,
891 pi0, pi1, next0, next1);
892 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000893
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100894 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500895 {
896 ip_lookup_next_t next0;
897 const load_balance_t *lb0;
898 vlib_buffer_t *p0;
899 u32 pi0, lbi0, hc0;
900 const ip6_header_t *ip0;
901 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100902
Dave Barachd7cb1b52016-12-09 09:52:16 -0500903 pi0 = from[0];
904 to_next[0] = pi0;
905 from += 1;
906 to_next += 1;
907 n_left_to_next -= 1;
908 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100909
Dave Barachd7cb1b52016-12-09 09:52:16 -0500910 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100911
Dave Barachd7cb1b52016-12-09 09:52:16 -0500912 ip0 = vlib_buffer_get_current (p0);
913 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100916
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000917 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500918 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
919 {
920 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
921 {
922 hc0 = vnet_buffer (p0)->ip.flow_hash =
923 vnet_buffer (p0)->ip.flow_hash >> 1;
924 }
925 else
926 {
927 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000928 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500929 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700930 dpo0 =
931 load_balance_get_fwd_bucket (lb0,
932 (hc0 &
933 lb0->lb_n_buckets_minus_1));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500934 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700935 else
936 {
937 dpo0 = load_balance_get_bucket_i (lb0, 0);
938 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100939
Dave Barachd7cb1b52016-12-09 09:52:16 -0500940 next0 = dpo0->dpoi_next_node;
941 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000942
Dave Barachd7cb1b52016-12-09 09:52:16 -0500943 /* Only process the HBH Option Header if explicitly configured to do so */
944 if (PREDICT_FALSE
945 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
946 {
947 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
948 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
949 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000950
Dave Barachd7cb1b52016-12-09 09:52:16 -0500951 vlib_increment_combined_counter
Damjan Marion586afd72017-04-05 19:18:20 +0200952 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100953
Dave Barachd7cb1b52016-12-09 09:52:16 -0500954 vlib_validate_buffer_enqueue_x1 (vm, node, next,
955 to_next, n_left_to_next,
956 pi0, next0);
957 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958
959 vlib_put_next_frame (vm, node, next, n_left_to_next);
960 }
961
962 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200963}
964
Dave Barachd7cb1b52016-12-09 09:52:16 -0500965/* *INDENT-OFF* */
966VLIB_REGISTER_NODE (ip6_load_balance_node) =
967{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100968 .function = ip6_load_balance,
969 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200970 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200971 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100972 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200973};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500974/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200977
Dave Barachd7cb1b52016-12-09 09:52:16 -0500978typedef struct
979{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980 /* Adjacency taken. */
981 u32 adj_index;
982 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500983 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984
985 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500986 u8 packet_data[128 - 1 * sizeof (u32)];
987}
988ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
John Lo2b81eb82017-01-30 13:12:10 -0500990u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100993 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
994 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500995 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +0200996 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100997
Dave Barachd7cb1b52016-12-09 09:52:16 -0500998 s = format (s, "%U%U",
999 format_white_space, indent,
1000 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001001 return s;
1002}
1003
Dave Barachd7cb1b52016-12-09 09:52:16 -05001004static u8 *
1005format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001006{
1007 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1008 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001010 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011
John Loac8146c2016-09-27 17:44:02 -04001012 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013 t->fib_index, t->adj_index, t->flow_hash);
1014 s = format (s, "\n%U%U",
1015 format_white_space, indent,
1016 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001017 return s;
1018}
Pierre Pfister0febaf12016-06-08 12:23:21 +01001019
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021static u8 *
1022format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001023{
1024 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1025 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001026 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001027 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001028
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001029 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001030 t->fib_index, t->adj_index, format_ip_adjacency,
1031 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001032 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001033 format_white_space, indent,
1034 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001035 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036 return s;
1037}
1038
1039/* Common trace function for all ip6-forward next nodes. */
1040void
1041ip6_forward_next_trace (vlib_main_t * vm,
1042 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001043 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001044{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001045 u32 *from, n_left;
1046 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047
1048 n_left = frame->n_vectors;
1049 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001050
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 while (n_left >= 4)
1052 {
1053 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001054 vlib_buffer_t *b0, *b1;
1055 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
1057 /* Prefetch next iteration. */
1058 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1059 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1060
1061 bi0 = from[0];
1062 bi1 = from[1];
1063
1064 b0 = vlib_get_buffer (vm, bi0);
1065 b1 = vlib_get_buffer (vm, bi1);
1066
1067 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1068 {
1069 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1070 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001071 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1072 t0->fib_index =
1073 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1074 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1075 vec_elt (im->fib_index_by_sw_if_index,
1076 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001077
Damjan Marionf1213b82016-03-13 02:22:06 +01001078 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001079 vlib_buffer_get_current (b0),
1080 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081 }
1082 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1083 {
1084 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1085 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001086 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1087 t1->fib_index =
1088 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1089 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1090 vec_elt (im->fib_index_by_sw_if_index,
1091 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001092
Damjan Marionf1213b82016-03-13 02:22:06 +01001093 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001094 vlib_buffer_get_current (b1),
1095 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 }
1097 from += 2;
1098 n_left -= 2;
1099 }
1100
1101 while (n_left >= 1)
1102 {
1103 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001104 vlib_buffer_t *b0;
1105 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106
1107 bi0 = from[0];
1108
1109 b0 = vlib_get_buffer (vm, bi0);
1110
1111 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1112 {
1113 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1114 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001115 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1116 t0->fib_index =
1117 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1118 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1119 vec_elt (im->fib_index_by_sw_if_index,
1120 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001121
Damjan Marionf1213b82016-03-13 02:22:06 +01001122 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001123 vlib_buffer_get_current (b0),
1124 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125 }
1126 from += 1;
1127 n_left -= 1;
1128 }
1129}
1130
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001132u16
1133ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1134 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135{
1136 ip_csum_t sum0;
1137 u16 sum16, payload_length_host_byte_order;
1138 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001139 u32 headers_size = sizeof (ip0[0]);
1140 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
Dave Barachd7cb1b52016-12-09 09:52:16 -05001142 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143 *bogus_lengthp = 0;
1144
1145 /* Initialize checksum with ip header. */
1146 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1147 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1148 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001149
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1151 {
1152 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001153 clib_mem_unaligned (&ip0->
1154 src_address.as_uword[i],
1155 uword));
1156 sum0 =
1157 ip_csum_with_carry (sum0,
1158 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1159 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160 }
1161
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301162 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1163 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001164 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001166 u32 skip_bytes;
1167 ip6_hop_by_hop_ext_t *ext_hdr =
1168 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001169
1170 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301171 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1172 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
Dave Barachd7cb1b52016-12-09 09:52:16 -05001174 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1175 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001179 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001180
1181 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182 if (p0 && n_this_buffer + headers_size > p0->current_length)
1183 n_this_buffer =
1184 p0->current_length >
1185 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186 while (1)
1187 {
1188 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1189 n_bytes_left -= n_this_buffer;
1190 if (n_bytes_left == 0)
1191 break;
1192
1193 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001194 {
1195 *bogus_lengthp = 1;
1196 return 0xfefe;
1197 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198 p0 = vlib_get_buffer (vm, p0->next_buffer);
1199 data_this_buffer = vlib_buffer_get_current (p0);
1200 n_this_buffer = p0->current_length;
1201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202
Dave Barachd7cb1b52016-12-09 09:52:16 -05001203 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001204
1205 return sum16;
1206}
1207
Dave Barachd7cb1b52016-12-09 09:52:16 -05001208u32
1209ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001211 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1212 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 u16 sum16;
1214 int bogus_length;
1215
1216 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1217 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1218 || ip0->protocol == IP_PROTOCOL_ICMP6
1219 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001220 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221
1222 udp0 = (void *) (ip0 + 1);
1223 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1224 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001225 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1226 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227 return p0->flags;
1228 }
1229
1230 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1231
Damjan Marion213b5aa2017-07-13 21:19:27 +02001232 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1233 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234
1235 return p0->flags;
1236}
1237
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301238/**
1239 * @brief returns number of links on which src is reachable.
1240 */
1241always_inline int
1242ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1243{
1244 const load_balance_t *lb0;
1245 index_t lbi;
1246
1247 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1248 vnet_buffer
1249 (b)->sw_if_index[VLIB_RX],
1250 &i->src_address);
1251
1252 lb0 = load_balance_get (lbi);
1253
1254 return (fib_urpf_check_size (lb0->lb_urpf));
1255}
1256
rootc9d1c5b2017-08-15 12:58:31 -04001257always_inline u8
1258ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0,
1259 u32 * udp_offset0)
1260{
1261 u32 proto0;
1262 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1263 if (proto0 != IP_PROTOCOL_UDP)
1264 {
1265 proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1266 proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1267 }
1268 return proto0;
1269}
1270
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001271/* *INDENT-OFF* */
1272VNET_FEATURE_ARC_INIT (ip6_local) =
1273{
1274 .arc_name = "ip6-local",
1275 .start_nodes = VNET_FEATURES ("ip6-local"),
1276};
1277/* *INDENT-ON* */
1278
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279static uword
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001280ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
1281 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001282{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001283 ip6_main_t *im = &ip6_main;
1284 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001286 u32 *from, *to_next, n_left_from, n_left_to_next;
1287 vlib_node_runtime_t *error_node =
1288 vlib_node_get_runtime (vm, ip6_input_node.index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001289 u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
1291 from = vlib_frame_vector_args (frame);
1292 n_left_from = frame->n_vectors;
1293 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001294
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295 if (node->flags & VLIB_NODE_FLAG_TRACE)
1296 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1297
1298 while (n_left_from > 0)
1299 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001300 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001301
1302 while (n_left_from >= 4 && n_left_to_next >= 2)
1303 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001304 vlib_buffer_t *p0, *p1;
1305 ip6_header_t *ip0, *ip1;
1306 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 u32 pi0, ip_len0, udp_len0, flags0, next0;
1308 u32 pi1, ip_len1, udp_len1, flags1, next1;
1309 i32 len_diff0, len_diff1;
rootc9d1c5b2017-08-15 12:58:31 -04001310 u8 error0, type0, good_l4_csum0, is_tcp_udp0;
1311 u8 error1, type1, good_l4_csum1, is_tcp_udp1;
Shwethab78292e2016-09-13 11:51:00 +01001312 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001313
Ed Warnickecb9cada2015-12-08 15:45:58 -07001314 pi0 = to_next[0] = from[0];
1315 pi1 = to_next[1] = from[1];
1316 from += 2;
1317 n_left_from -= 2;
1318 to_next += 2;
1319 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001320
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001321 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1322
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 p0 = vlib_get_buffer (vm, pi0);
1324 p1 = vlib_get_buffer (vm, pi1);
1325
1326 ip0 = vlib_buffer_get_current (p0);
1327 ip1 = vlib_buffer_get_current (p1);
1328
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001329 if (head_of_feature_arc == 0)
1330 goto skip_checks;
1331
Damjan Marion072401e2017-07-13 18:53:27 +02001332 vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1333 vnet_buffer (p1)->l3_hdr_offset = p1->current_data;
Filip Tehlarb601f222017-01-02 10:22:56 +01001334
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1336 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1337
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 flags0 = p0->flags;
1339 flags1 = p1->flags;
1340
rootc9d1c5b2017-08-15 12:58:31 -04001341 is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1342 is_tcp_udp1 = ip6_next_proto_is_tcp_udp (p1, ip1, &udp_offset1);
1343
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 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001905 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-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 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001923 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1924 [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 {
2232 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2233 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2234 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002235 if (is_mcast)
2236 {
2237 /*
2238 * copy bytes from the IP address into the MAC rewrite
2239 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002240 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2241 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002242 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002243
Ed Warnickecb9cada2015-12-08 15:45:58 -07002244 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2245 to_next, n_left_to_next,
2246 pi0, pi1, next0, next1);
2247 }
2248
2249 while (n_left_from > 0 && n_left_to_next > 0)
2250 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002251 ip_adjacency_t *adj0;
2252 vlib_buffer_t *p0;
2253 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002254 u32 pi0, rw_len0;
2255 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002257
Ed Warnickecb9cada2015-12-08 15:45:58 -07002258 pi0 = to_next[0] = from[0];
2259
2260 p0 = vlib_get_buffer (vm, pi0);
2261
Neale Rannsf06aea52016-11-29 06:51:37 -08002262 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002263
Neale Ranns107e7d42017-04-11 09:55:19 -07002264 adj0 = adj_get (adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002265
Ed Warnickecb9cada2015-12-08 15:45:58 -07002266 ip0 = vlib_buffer_get_current (p0);
2267
2268 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002269 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002270
2271 /* Check hop limit */
Damjan Marion213b5aa2017-07-13 21:19:27 +02002272 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002273 {
2274 i32 hop_limit0 = ip0->hop_limit;
2275
2276 ASSERT (ip0->hop_limit > 0);
2277
2278 hop_limit0 -= 1;
2279
2280 ip0->hop_limit = hop_limit0;
2281
Dave Barachd7cb1b52016-12-09 09:52:16 -05002282 if (PREDICT_FALSE (hop_limit0 <= 0))
2283 {
2284 /*
2285 * If the hop count drops below 1 when forwarding, generate
2286 * an ICMP response.
2287 */
2288 error0 = IP6_ERROR_TIME_EXPIRED;
2289 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2290 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2291 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2292 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2293 0);
2294 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002295 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002296 else
2297 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02002298 p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002299 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002300
Ed Warnickecb9cada2015-12-08 15:45:58 -07002301 /* Guess we are only writing on simple Ethernet header. */
2302 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002303
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 /* Update packet buffer attributes/set output interface. */
2305 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002306 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002307
Neale Ranns9c6a6132017-02-21 05:33:14 -08002308 if (do_counters)
2309 {
2310 vlib_increment_combined_counter
2311 (&adjacency_counters,
Damjan Marion586afd72017-04-05 19:18:20 +02002312 thread_index, adj_index0, 1,
Neale Ranns9c6a6132017-02-21 05:33:14 -08002313 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2314 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002315
2316 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002317 error0 =
2318 (vlib_buffer_length_in_chain (vm, p0) >
2319 adj0[0].
2320 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2321 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002322
Dave Barachd7cb1b52016-12-09 09:52:16 -05002323 /* Don't adjust the buffer for hop count issue; icmp-error node
2324 * wants to see the IP headerr */
2325 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2326 {
Chris Luke816f3e12016-06-14 16:24:47 -04002327 p0->current_data -= rw_len0;
2328 p0->current_length += rw_len0;
2329
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002331
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2333 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002334
Neale Rannsb069a692017-03-15 12:34:25 -04002335 if (PREDICT_FALSE
2336 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2337 vnet_feature_arc_start (lm->output_feature_arc_index,
2338 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002339 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002340
Neale Ranns5e575b12016-10-03 09:40:25 +01002341 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002342 {
2343 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2344 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002345 if (is_mcast)
2346 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002347 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002348 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002349
Ed Warnickecb9cada2015-12-08 15:45:58 -07002350 p0->error = error_node->errors[error0];
2351
2352 from += 1;
2353 n_left_from -= 1;
2354 to_next += 1;
2355 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002356
Ed Warnickecb9cada2015-12-08 15:45:58 -07002357 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2358 to_next, n_left_to_next,
2359 pi0, next0);
2360 }
2361
2362 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2363 }
2364
2365 /* Need to do trace after rewrites to pick up new packet data. */
2366 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002367 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002368
2369 return frame->n_vectors;
2370}
2371
2372static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002373ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002374 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002375{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002376 if (adj_are_counters_enabled ())
2377 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2378 else
2379 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002380}
2381
2382static uword
2383ip6_rewrite_mcast (vlib_main_t * vm,
2384 vlib_node_runtime_t * node, vlib_frame_t * frame)
2385{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002386 if (adj_are_counters_enabled ())
2387 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2388 else
2389 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002390}
2391
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002392static uword
2393ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002395{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002396 if (adj_are_counters_enabled ())
2397 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2398 else
2399 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002400}
2401
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002402static uword
2403ip6_mcast_midchain (vlib_main_t * vm,
2404 vlib_node_runtime_t * node, vlib_frame_t * frame)
2405{
2406 if (adj_are_counters_enabled ())
2407 return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2408 else
Neale Ranns9f171f52017-04-11 08:56:53 -07002409 return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002410}
2411
Dave Barachd7cb1b52016-12-09 09:52:16 -05002412/* *INDENT-OFF* */
2413VLIB_REGISTER_NODE (ip6_midchain_node) =
2414{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002415 .function = ip6_midchain,
2416 .name = "ip6-midchain",
2417 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002418 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002419 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002420 };
2421/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002422
Dave Barachd7cb1b52016-12-09 09:52:16 -05002423VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002424
Dave Barachd7cb1b52016-12-09 09:52:16 -05002425/* *INDENT-OFF* */
2426VLIB_REGISTER_NODE (ip6_rewrite_node) =
2427{
Neale Rannsf06aea52016-11-29 06:51:37 -08002428 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002429 .name = "ip6-rewrite",
2430 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002431 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002432 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002433 .next_nodes =
2434 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002435 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002436 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002437 },
2438};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002439/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002440
Neale Rannsf06aea52016-11-29 06:51:37 -08002441VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002442
Neale Ranns32e1c012016-11-22 17:07:28 +00002443/* *INDENT-OFF* */
2444VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2445{
2446 .function = ip6_rewrite_mcast,
2447 .name = "ip6-rewrite-mcast",
2448 .vector_size = sizeof (u32),
2449 .format_trace = format_ip6_rewrite_trace,
2450 .sibling_of = "ip6-rewrite",
2451};
2452/* *INDENT-ON* */
2453
2454VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2455
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002456/* *INDENT-OFF* */
2457VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
2458{
2459 .function = ip6_mcast_midchain,
2460 .name = "ip6-mcast-midchain",
2461 .vector_size = sizeof (u32),
2462 .format_trace = format_ip6_rewrite_trace,
2463 .sibling_of = "ip6-rewrite",
2464};
2465/* *INDENT-ON* */
2466
2467VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2468
Ole Troan944f5482016-05-24 11:56:58 +02002469/*
2470 * Hop-by-Hop handling
2471 */
Ole Troan944f5482016-05-24 11:56:58 +02002472ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2473
2474#define foreach_ip6_hop_by_hop_error \
2475_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2476_(FORMAT, "incorrectly formatted hop-by-hop options") \
2477_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2478
Neale Ranns32e1c012016-11-22 17:07:28 +00002479/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002480typedef enum
2481{
Ole Troan944f5482016-05-24 11:56:58 +02002482#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2483 foreach_ip6_hop_by_hop_error
2484#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002485 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002486} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002487/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002488
2489/*
2490 * Primary h-b-h handler trace support
2491 * We work pretty hard on the problem for obvious reasons
2492 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002493typedef struct
2494{
Ole Troan944f5482016-05-24 11:56:58 +02002495 u32 next_index;
2496 u32 trace_len;
2497 u8 option_data[256];
2498} ip6_hop_by_hop_trace_t;
2499
2500vlib_node_registration_t ip6_hop_by_hop_node;
2501
Dave Barachd7cb1b52016-12-09 09:52:16 -05002502static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002503#define _(sym,string) string,
2504 foreach_ip6_hop_by_hop_error
2505#undef _
2506};
2507
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302508u8 *
2509format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2510{
2511 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2512 int total_len = va_arg (*args, int);
2513 ip6_hop_by_hop_option_t *opt0, *limit0;
2514 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2515 u8 type0;
2516
2517 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2518 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2519
2520 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2521 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2522
2523 while (opt0 < limit0)
2524 {
2525 type0 = opt0->type;
2526 switch (type0)
2527 {
2528 case 0: /* Pad, just stop */
2529 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2530 break;
2531
2532 default:
2533 if (hm->trace[type0])
2534 {
2535 s = (*hm->trace[type0]) (s, opt0);
2536 }
2537 else
2538 {
2539 s =
2540 format (s, "\n unrecognized option %d length %d", type0,
2541 opt0->length);
2542 }
2543 opt0 =
2544 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2545 sizeof (ip6_hop_by_hop_option_t));
2546 break;
2547 }
2548 }
2549 return s;
2550}
2551
Ole Troan944f5482016-05-24 11:56:58 +02002552static u8 *
2553format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2554{
2555 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2556 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002557 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002558 ip6_hop_by_hop_header_t *hbh0;
2559 ip6_hop_by_hop_option_t *opt0, *limit0;
2560 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2561
2562 u8 type0;
2563
Dave Barachd7cb1b52016-12-09 09:52:16 -05002564 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002565
2566 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002567 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002568
Dave Barachd7cb1b52016-12-09 09:52:16 -05002569 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2570 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002571
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 while (opt0 < limit0)
2573 {
2574 type0 = opt0->type;
2575 switch (type0)
2576 {
2577 case 0: /* Pad, just stop */
2578 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2579 break;
Ole Troan944f5482016-05-24 11:56:58 +02002580
Dave Barachd7cb1b52016-12-09 09:52:16 -05002581 default:
2582 if (hm->trace[type0])
2583 {
2584 s = (*hm->trace[type0]) (s, opt0);
2585 }
2586 else
2587 {
2588 s =
2589 format (s, "\n unrecognized option %d length %d", type0,
2590 opt0->length);
2591 }
2592 opt0 =
2593 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2594 sizeof (ip6_hop_by_hop_option_t));
2595 break;
2596 }
Ole Troan944f5482016-05-24 11:56:58 +02002597 }
Ole Troan944f5482016-05-24 11:56:58 +02002598 return s;
2599}
2600
Dave Barachd7cb1b52016-12-09 09:52:16 -05002601always_inline u8
2602ip6_scan_hbh_options (vlib_buffer_t * b0,
2603 ip6_header_t * ip0,
2604 ip6_hop_by_hop_header_t * hbh0,
2605 ip6_hop_by_hop_option_t * opt0,
2606 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002607{
2608 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2609 u8 type0;
2610 u8 error0 = 0;
2611
2612 while (opt0 < limit0)
2613 {
2614 type0 = opt0->type;
2615 switch (type0)
2616 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002617 case 0: /* Pad1 */
2618 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002619 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002620 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002621 break;
2622 default:
2623 if (hm->options[type0])
2624 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002625 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2626 {
Shwethaa91cbe62016-08-08 15:51:04 +01002627 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002628 return (error0);
2629 }
Shwethaa91cbe62016-08-08 15:51:04 +01002630 }
2631 else
2632 {
2633 /* Unrecognized mandatory option, check the two high order bits */
2634 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2635 {
2636 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2637 break;
2638 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2639 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2640 *next0 = IP_LOOKUP_NEXT_DROP;
2641 break;
2642 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2643 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2644 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002645 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2646 ICMP6_parameter_problem_unrecognized_option,
2647 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002648 break;
2649 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2650 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002651 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002652 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002653 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2654 icmp6_error_set_vnet_buffer (b0,
2655 ICMP6_parameter_problem,
2656 ICMP6_parameter_problem_unrecognized_option,
2657 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002658 }
2659 else
2660 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002661 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002662 }
2663 break;
2664 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002665 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002666 }
2667 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002668 opt0 =
2669 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2670 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002671 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002672 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002673}
2674
Ole Troan944f5482016-05-24 11:56:58 +02002675/*
2676 * Process the Hop-by-Hop Options header
2677 */
2678static uword
2679ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002680 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002681{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002682 vlib_node_runtime_t *error_node =
2683 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002684 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2685 u32 n_left_from, *from, *to_next;
2686 ip_lookup_next_t next_index;
Ole Troan944f5482016-05-24 11:56:58 +02002687
2688 from = vlib_frame_vector_args (frame);
2689 n_left_from = frame->n_vectors;
2690 next_index = node->cached_next_index;
2691
Dave Barachd7cb1b52016-12-09 09:52:16 -05002692 while (n_left_from > 0)
2693 {
2694 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002695
Dave Barachd7cb1b52016-12-09 09:52:16 -05002696 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002697
Dave Barachd7cb1b52016-12-09 09:52:16 -05002698 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002699 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002700 u32 bi0, bi1;
2701 vlib_buffer_t *b0, *b1;
2702 u32 next0, next1;
2703 ip6_header_t *ip0, *ip1;
2704 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2705 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2706 u8 error0 = 0, error1 = 0;
2707
2708 /* Prefetch next iteration. */
2709 {
2710 vlib_buffer_t *p2, *p3;
2711
2712 p2 = vlib_get_buffer (vm, from[2]);
2713 p3 = vlib_get_buffer (vm, from[3]);
2714
2715 vlib_prefetch_buffer_header (p2, LOAD);
2716 vlib_prefetch_buffer_header (p3, LOAD);
2717
2718 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2719 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002720 }
2721
Dave Barachd7cb1b52016-12-09 09:52:16 -05002722 /* Speculatively enqueue b0, b1 to the current next frame */
2723 to_next[0] = bi0 = from[0];
2724 to_next[1] = bi1 = from[1];
2725 from += 2;
2726 to_next += 2;
2727 n_left_from -= 2;
2728 n_left_to_next -= 2;
2729
2730 b0 = vlib_get_buffer (vm, bi0);
2731 b1 = vlib_get_buffer (vm, bi1);
2732
2733 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2734 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002735 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002736 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002737 ip_adjacency_t *adj1 = adj_get (adj_index1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002738
2739 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2740 next0 = adj0->lookup_next_index;
2741 next1 = adj1->lookup_next_index;
2742
2743 ip0 = vlib_buffer_get_current (b0);
2744 ip1 = vlib_buffer_get_current (b1);
2745 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2746 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2747 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2748 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2749 limit0 =
2750 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2751 ((hbh0->length + 1) << 3));
2752 limit1 =
2753 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2754 ((hbh1->length + 1) << 3));
2755
2756 /*
2757 * Basic validity checks
2758 */
2759 if ((hbh0->length + 1) << 3 >
2760 clib_net_to_host_u16 (ip0->payload_length))
2761 {
2762 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2763 next0 = IP_LOOKUP_NEXT_DROP;
2764 goto outdual;
2765 }
2766 /* Scan the set of h-b-h options, process ones that we understand */
2767 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2768
2769 if ((hbh1->length + 1) << 3 >
2770 clib_net_to_host_u16 (ip1->payload_length))
2771 {
2772 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2773 next1 = IP_LOOKUP_NEXT_DROP;
2774 goto outdual;
2775 }
2776 /* Scan the set of h-b-h options, process ones that we understand */
2777 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2778
2779 outdual:
2780 /* Has the classifier flagged this buffer for special treatment? */
2781 if (PREDICT_FALSE
2782 ((error0 == 0)
2783 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2784 next0 = hm->next_override;
2785
2786 /* Has the classifier flagged this buffer for special treatment? */
2787 if (PREDICT_FALSE
2788 ((error1 == 0)
2789 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2790 next1 = hm->next_override;
2791
2792 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2793 {
2794 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2795 {
2796 ip6_hop_by_hop_trace_t *t =
2797 vlib_add_trace (vm, node, b0, sizeof (*t));
2798 u32 trace_len = (hbh0->length + 1) << 3;
2799 t->next_index = next0;
2800 /* Capture the h-b-h option verbatim */
2801 trace_len =
2802 trace_len <
2803 ARRAY_LEN (t->option_data) ? trace_len :
2804 ARRAY_LEN (t->option_data);
2805 t->trace_len = trace_len;
2806 clib_memcpy (t->option_data, hbh0, trace_len);
2807 }
2808 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2809 {
2810 ip6_hop_by_hop_trace_t *t =
2811 vlib_add_trace (vm, node, b1, sizeof (*t));
2812 u32 trace_len = (hbh1->length + 1) << 3;
2813 t->next_index = next1;
2814 /* Capture the h-b-h option verbatim */
2815 trace_len =
2816 trace_len <
2817 ARRAY_LEN (t->option_data) ? trace_len :
2818 ARRAY_LEN (t->option_data);
2819 t->trace_len = trace_len;
2820 clib_memcpy (t->option_data, hbh1, trace_len);
2821 }
2822
2823 }
2824
2825 b0->error = error_node->errors[error0];
2826 b1->error = error_node->errors[error1];
2827
2828 /* verify speculative enqueue, maybe switch current next frame */
2829 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2830 n_left_to_next, bi0, bi1, next0,
2831 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002832 }
2833
Dave Barachd7cb1b52016-12-09 09:52:16 -05002834 while (n_left_from > 0 && n_left_to_next > 0)
2835 {
2836 u32 bi0;
2837 vlib_buffer_t *b0;
2838 u32 next0;
2839 ip6_header_t *ip0;
2840 ip6_hop_by_hop_header_t *hbh0;
2841 ip6_hop_by_hop_option_t *opt0, *limit0;
2842 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002843
Dave Barachd7cb1b52016-12-09 09:52:16 -05002844 /* Speculatively enqueue b0 to the current next frame */
2845 bi0 = from[0];
2846 to_next[0] = bi0;
2847 from += 1;
2848 to_next += 1;
2849 n_left_from -= 1;
2850 n_left_to_next -= 1;
2851
2852 b0 = vlib_get_buffer (vm, bi0);
2853 /*
2854 * Default use the next_index from the adjacency.
2855 * A HBH option rarely redirects to a different node
2856 */
2857 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
Neale Ranns107e7d42017-04-11 09:55:19 -07002858 ip_adjacency_t *adj0 = adj_get (adj_index0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002859 next0 = adj0->lookup_next_index;
2860
2861 ip0 = vlib_buffer_get_current (b0);
2862 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2863 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2864 limit0 =
2865 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2866 ((hbh0->length + 1) << 3));
2867
2868 /*
2869 * Basic validity checks
2870 */
2871 if ((hbh0->length + 1) << 3 >
2872 clib_net_to_host_u16 (ip0->payload_length))
2873 {
2874 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2875 next0 = IP_LOOKUP_NEXT_DROP;
2876 goto out0;
2877 }
2878
2879 /* Scan the set of h-b-h options, process ones that we understand */
2880 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2881
2882 out0:
2883 /* Has the classifier flagged this buffer for special treatment? */
2884 if (PREDICT_FALSE
2885 ((error0 == 0)
2886 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2887 next0 = hm->next_override;
2888
2889 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2890 {
2891 ip6_hop_by_hop_trace_t *t =
2892 vlib_add_trace (vm, node, b0, sizeof (*t));
2893 u32 trace_len = (hbh0->length + 1) << 3;
2894 t->next_index = next0;
2895 /* Capture the h-b-h option verbatim */
2896 trace_len =
2897 trace_len <
2898 ARRAY_LEN (t->option_data) ? trace_len :
2899 ARRAY_LEN (t->option_data);
2900 t->trace_len = trace_len;
2901 clib_memcpy (t->option_data, hbh0, trace_len);
2902 }
2903
2904 b0->error = error_node->errors[error0];
2905
2906 /* verify speculative enqueue, maybe switch current next frame */
2907 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2908 n_left_to_next, bi0, next0);
2909 }
2910 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002911 }
Ole Troan944f5482016-05-24 11:56:58 +02002912 return frame->n_vectors;
2913}
2914
Dave Barachd7cb1b52016-12-09 09:52:16 -05002915/* *INDENT-OFF* */
2916VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2917{
Ole Troan944f5482016-05-24 11:56:58 +02002918 .function = ip6_hop_by_hop,
2919 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002920 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002921 .vector_size = sizeof (u32),
2922 .format_trace = format_ip6_hop_by_hop_trace,
2923 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002924 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002925 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002926 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002927};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002928/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002929
Dave Barach5331c722016-08-17 11:54:30 -04002930VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002931
2932static clib_error_t *
2933ip6_hop_by_hop_init (vlib_main_t * vm)
2934{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002935 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2936 memset (hm->options, 0, sizeof (hm->options));
2937 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002938 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002939 return (0);
2940}
2941
2942VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2943
Dave Barachd7cb1b52016-12-09 09:52:16 -05002944void
2945ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002946{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002947 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002948
2949 hm->next_override = next;
2950}
2951
Ole Troan944f5482016-05-24 11:56:58 +02002952int
2953ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002954 int options (vlib_buffer_t * b, ip6_header_t * ip,
2955 ip6_hop_by_hop_option_t * opt),
2956 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002957{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002958 ip6_main_t *im = &ip6_main;
2959 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002960
2961 ASSERT (option < ARRAY_LEN (hm->options));
2962
2963 /* Already registered */
2964 if (hm->options[option])
2965 return (-1);
2966
2967 hm->options[option] = options;
2968 hm->trace[option] = trace;
2969
2970 /* Set global variable */
2971 im->hbh_enabled = 1;
2972
2973 return (0);
2974}
2975
2976int
2977ip6_hbh_unregister_option (u8 option)
2978{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002979 ip6_main_t *im = &ip6_main;
2980 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002981
2982 ASSERT (option < ARRAY_LEN (hm->options));
2983
2984 /* Not registered */
2985 if (!hm->options[option])
2986 return (-1);
2987
2988 hm->options[option] = NULL;
2989 hm->trace[option] = NULL;
2990
2991 /* Disable global knob if this was the last option configured */
2992 int i;
2993 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002994 for (i = 0; i < 256; i++)
2995 {
2996 if (hm->options[option])
2997 {
2998 found = true;
2999 break;
3000 }
Ole Troan944f5482016-05-24 11:56:58 +02003001 }
Ole Troan944f5482016-05-24 11:56:58 +02003002 if (!found)
3003 im->hbh_enabled = 0;
3004
3005 return (0);
3006}
3007
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008/* Global IP6 main. */
3009ip6_main_t ip6_main;
3010
3011static clib_error_t *
3012ip6_lookup_init (vlib_main_t * vm)
3013{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003014 ip6_main_t *im = &ip6_main;
3015 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003016 uword i;
3017
Damjan Marion8b3191e2016-11-09 19:54:20 +01003018 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
3019 return error;
3020
Ed Warnickecb9cada2015-12-08 15:45:58 -07003021 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
3022 {
3023 u32 j, i0, i1;
3024
3025 i0 = i / 32;
3026 i1 = i % 32;
3027
3028 for (j = 0; j < i0; j++)
3029 im->fib_masks[i].as_u32[j] = ~0;
3030
3031 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003032 im->fib_masks[i].as_u32[i0] =
3033 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003034 }
3035
3036 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
3037
3038 if (im->lookup_table_nbuckets == 0)
3039 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
3040
Dave Barachd7cb1b52016-12-09 09:52:16 -05003041 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003042
3043 if (im->lookup_table_size == 0)
3044 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04003045
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
3047 "ip6 FIB fwding table",
3048 im->lookup_table_nbuckets, im->lookup_table_size);
3049 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
3050 "ip6 FIB non-fwding table",
3051 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003052
Ed Warnickecb9cada2015-12-08 15:45:58 -07003053 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07003054 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3055 FIB_SOURCE_DEFAULT_ROUTE);
3056 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
3057 MFIB_SOURCE_DEFAULT_ROUTE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003058
3059 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003060 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061 pn = pg_get_node (ip6_lookup_node.index);
3062 pn->unformat_edit = unformat_pg_ip6_header;
3063 }
3064
Ole Troan944f5482016-05-24 11:56:58 +02003065 /* Unless explicitly configured, don't process HBH options */
3066 im->hbh_enabled = 0;
3067
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068 {
3069 icmp6_neighbor_solicitation_header_t p;
3070
3071 memset (&p, 0, sizeof (p));
3072
Dave Barachd7cb1b52016-12-09 09:52:16 -05003073 p.ip.ip_version_traffic_class_and_flow_label =
3074 clib_host_to_net_u32 (0x6 << 28);
3075 p.ip.payload_length =
3076 clib_host_to_net_u16 (sizeof (p) -
3077 STRUCT_OFFSET_OF
3078 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07003079 p.ip.protocol = IP_PROTOCOL_ICMP6;
3080 p.ip.hop_limit = 255;
3081 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
3082
3083 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
3084
Dave Barachd7cb1b52016-12-09 09:52:16 -05003085 p.link_layer_option.header.type =
3086 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3087 p.link_layer_option.header.n_data_u64s =
3088 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003089
3090 vlib_packet_template_init (vm,
3091 &im->discover_neighbor_packet_template,
3092 &p, sizeof (p),
3093 /* alloc chunk size */ 8,
3094 "ip6 neighbor discovery");
3095 }
3096
Dave Barach203c6322016-06-26 10:29:03 -04003097 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003098}
3099
3100VLIB_INIT_FUNCTION (ip6_lookup_init);
3101
Dave Barach75fc8542016-10-11 16:16:02 -04003102void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003103ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3104 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105{
3106 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3107 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003108 ip->as_u8[8] = mac[0] ^ (1 << 1);
3109 ip->as_u8[9] = mac[1];
3110 ip->as_u8[10] = mac[2];
3111 ip->as_u8[11] = 0xFF;
3112 ip->as_u8[12] = 0xFE;
3113 ip->as_u8[13] = mac[3];
3114 ip->as_u8[14] = mac[4];
3115 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003116}
3117
Dave Barach75fc8542016-10-11 16:16:02 -04003118void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3120 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003121{
3122 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003123 mac[0] = ip->as_u8[8] ^ (1 << 1);
3124 mac[1] = ip->as_u8[9];
3125 mac[2] = ip->as_u8[10];
3126 mac[3] = ip->as_u8[13];
3127 mac[4] = ip->as_u8[14];
3128 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003129}
3130
Dave Barach75fc8542016-10-11 16:16:02 -04003131static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003132test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003133 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134{
3135 u8 mac[6];
3136 ip6_address_t _a, *a = &_a;
3137
3138 if (unformat (input, "%U", unformat_ethernet_address, mac))
3139 {
3140 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003141 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3143 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003144 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003145 }
Dave Barach75fc8542016-10-11 16:16:02 -04003146
Ed Warnickecb9cada2015-12-08 15:45:58 -07003147 return 0;
3148}
3149
Billy McFall0683c9c2016-10-13 08:27:31 -04003150/*?
3151 * This command converts the given MAC Address into an IPv6 link-local
3152 * address.
3153 *
3154 * @cliexpar
3155 * Example of how to create an IPv6 link-local address:
3156 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3157 * Link local address: fe80::14d9:e0ff:fe91:7986
3158 * Original MAC address: 16:d9:e0:91:79:86
3159 * @cliexend
3160?*/
3161/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003162VLIB_CLI_COMMAND (test_link_command, static) =
3163{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003164 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003165 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003166 .short_help = "test ip6 link <mac-address>",
3167};
Billy McFall0683c9c2016-10-13 08:27:31 -04003168/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003169
Dave Barachd7cb1b52016-12-09 09:52:16 -05003170int
3171vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003172{
Neale Ranns107e7d42017-04-11 09:55:19 -07003173 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003174
Neale Ranns107e7d42017-04-11 09:55:19 -07003175 fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003176
Neale Ranns107e7d42017-04-11 09:55:19 -07003177 if (~0 == fib_index)
3178 return VNET_API_ERROR_NO_SUCH_FIB;
3179
Neale Ranns227038a2017-04-21 01:07:59 -07003180 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
3181 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003182
Neale Ranns227038a2017-04-21 01:07:59 -07003183 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003184}
3185
3186static clib_error_t *
3187set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003188 unformat_input_t * input,
3189 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003190{
3191 int matched = 0;
3192 u32 table_id = 0;
3193 u32 flow_hash_config = 0;
3194 int rv;
3195
Dave Barachd7cb1b52016-12-09 09:52:16 -05003196 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3197 {
3198 if (unformat (input, "table %d", &table_id))
3199 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003200#define _(a,v) \
3201 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003202 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003203#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003204 else
3205 break;
3206 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003207
3208 if (matched == 0)
3209 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003210 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003211
Ed Warnickecb9cada2015-12-08 15:45:58 -07003212 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3213 switch (rv)
3214 {
Neale Ranns227038a2017-04-21 01:07:59 -07003215 case 0:
Ed Warnickecb9cada2015-12-08 15:45:58 -07003216 break;
3217
3218 case -1:
3219 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003220
Ed Warnickecb9cada2015-12-08 15:45:58 -07003221 default:
3222 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3223 break;
3224 }
Dave Barach75fc8542016-10-11 16:16:02 -04003225
Ed Warnickecb9cada2015-12-08 15:45:58 -07003226 return 0;
3227}
3228
Billy McFall0683c9c2016-10-13 08:27:31 -04003229/*?
3230 * Configure the set of IPv6 fields used by the flow hash.
3231 *
3232 * @cliexpar
3233 * @parblock
3234 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003235 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3236 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003237 * Example of display the configured flow hash:
3238 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003239 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3240 * @::/0
3241 * unicast-ip6-chain
3242 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3243 * [0] [@0]: dpo-drop ip6
3244 * fe80::/10
3245 * unicast-ip6-chain
3246 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3247 * [0] [@2]: dpo-receive
3248 * ff02::1/128
3249 * unicast-ip6-chain
3250 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3251 * [0] [@2]: dpo-receive
3252 * ff02::2/128
3253 * unicast-ip6-chain
3254 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3255 * [0] [@2]: dpo-receive
3256 * ff02::16/128
3257 * unicast-ip6-chain
3258 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3259 * [0] [@2]: dpo-receive
3260 * ff02::1:ff00:0/104
3261 * unicast-ip6-chain
3262 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3263 * [0] [@2]: dpo-receive
3264 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3265 * @::/0
3266 * unicast-ip6-chain
3267 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3268 * [0] [@0]: dpo-drop ip6
3269 * @::a:1:1:0:4/126
3270 * unicast-ip6-chain
3271 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3272 * [0] [@4]: ipv6-glean: af_packet0
3273 * @::a:1:1:0:7/128
3274 * unicast-ip6-chain
3275 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3276 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3277 * fe80::/10
3278 * unicast-ip6-chain
3279 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3280 * [0] [@2]: dpo-receive
3281 * fe80::fe:3eff:fe3e:9222/128
3282 * unicast-ip6-chain
3283 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3284 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3285 * ff02::1/128
3286 * unicast-ip6-chain
3287 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3288 * [0] [@2]: dpo-receive
3289 * ff02::2/128
3290 * unicast-ip6-chain
3291 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3292 * [0] [@2]: dpo-receive
3293 * ff02::16/128
3294 * unicast-ip6-chain
3295 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3296 * [0] [@2]: dpo-receive
3297 * ff02::1:ff00:0/104
3298 * unicast-ip6-chain
3299 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3300 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003301 * @cliexend
3302 * @endparblock
3303?*/
3304/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003305VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3306{
3307 .path = "set ip6 flow-hash",
3308 .short_help =
3309 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3310 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003311};
Billy McFall0683c9c2016-10-13 08:27:31 -04003312/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003313
3314static clib_error_t *
3315show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003316 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003317{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003318 ip6_main_t *im = &ip6_main;
3319 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003320 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003321
Ed Warnickecb9cada2015-12-08 15:45:58 -07003322 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003323 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003324 {
3325 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02003326 {
3327
3328 u32 node_index = vlib_get_node (vm,
3329 ip6_local_node.index)->
3330 next_nodes[lm->local_next_by_ip_protocol[i]];
3331 vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
3332 node_index);
3333 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003334 }
3335 return 0;
3336}
3337
3338
3339
Billy McFall0683c9c2016-10-13 08:27:31 -04003340/*?
3341 * Display the set of protocols handled by the local IPv6 stack.
3342 *
3343 * @cliexpar
3344 * Example of how to display local protocol table:
3345 * @cliexstart{show ip6 local}
3346 * Protocols handled by ip6_local
3347 * 17
3348 * 43
3349 * 58
3350 * 115
3351 * @cliexend
3352?*/
3353/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003354VLIB_CLI_COMMAND (show_ip6_local, static) =
3355{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003356 .path = "show ip6 local",
3357 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003358 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003359};
Billy McFall0683c9c2016-10-13 08:27:31 -04003360/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003361
Dave Barachd7cb1b52016-12-09 09:52:16 -05003362int
3363vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3364 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003365{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003366 vnet_main_t *vnm = vnet_get_main ();
3367 vnet_interface_main_t *im = &vnm->interface_main;
3368 ip6_main_t *ipm = &ip6_main;
3369 ip_lookup_main_t *lm = &ipm->lookup_main;
3370 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003371 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003372
3373 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3374 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3375
3376 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3377 return VNET_API_ERROR_NO_SUCH_ENTRY;
3378
3379 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003380 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003381
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003382 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003383
3384 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003385 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003386 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003387 .fp_len = 128,
3388 .fp_proto = FIB_PROTOCOL_IP6,
3389 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003390 };
3391 u32 fib_index;
3392
Dave Barachd7cb1b52016-12-09 09:52:16 -05003393 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3394 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003395
3396
Dave Barachd7cb1b52016-12-09 09:52:16 -05003397 if (table_index != (u32) ~ 0)
3398 {
3399 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003400
Dave Barachd7cb1b52016-12-09 09:52:16 -05003401 dpo_set (&dpo,
3402 DPO_CLASSIFY,
3403 DPO_PROTO_IP6,
3404 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003405
Dave Barachd7cb1b52016-12-09 09:52:16 -05003406 fib_table_entry_special_dpo_add (fib_index,
3407 &pfx,
3408 FIB_SOURCE_CLASSIFY,
3409 FIB_ENTRY_FLAG_NONE, &dpo);
3410 dpo_reset (&dpo);
3411 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003412 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003413 {
3414 fib_table_entry_special_remove (fib_index,
3415 &pfx, FIB_SOURCE_CLASSIFY);
3416 }
3417 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003418
Ed Warnickecb9cada2015-12-08 15:45:58 -07003419 return 0;
3420}
3421
3422static clib_error_t *
3423set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003424 unformat_input_t * input,
3425 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003426{
3427 u32 table_index = ~0;
3428 int table_index_set = 0;
3429 u32 sw_if_index = ~0;
3430 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003431
Dave Barachd7cb1b52016-12-09 09:52:16 -05003432 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3433 {
3434 if (unformat (input, "table-index %d", &table_index))
3435 table_index_set = 1;
3436 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3437 vnet_get_main (), &sw_if_index))
3438 ;
3439 else
3440 break;
3441 }
Dave Barach75fc8542016-10-11 16:16:02 -04003442
Ed Warnickecb9cada2015-12-08 15:45:58 -07003443 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003444 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003445
Ed Warnickecb9cada2015-12-08 15:45:58 -07003446 if (sw_if_index == ~0)
3447 return clib_error_return (0, "interface / subif must be specified");
3448
3449 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3450
3451 switch (rv)
3452 {
3453 case 0:
3454 break;
3455
3456 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3457 return clib_error_return (0, "No such interface");
3458
3459 case VNET_API_ERROR_NO_SUCH_ENTRY:
3460 return clib_error_return (0, "No such classifier table");
3461 }
3462 return 0;
3463}
3464
Billy McFall0683c9c2016-10-13 08:27:31 -04003465/*?
3466 * Assign a classification table to an interface. The classification
3467 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3468 * commands. Once the table is create, use this command to filter packets
3469 * on an interface.
3470 *
3471 * @cliexpar
3472 * Example of how to assign a classification table to an interface:
3473 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3474?*/
3475/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003476VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3477{
3478 .path = "set ip6 classify",
3479 .short_help =
3480 "set ip6 classify intfc <interface> table-index <classify-idx>",
3481 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003482};
Billy McFall0683c9c2016-10-13 08:27:31 -04003483/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003484
3485static clib_error_t *
3486ip6_config (vlib_main_t * vm, unformat_input_t * input)
3487{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003488 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003489 uword heapsize = 0;
3490 u32 tmp;
3491 u32 nbuckets = 0;
3492
Dave Barachd7cb1b52016-12-09 09:52:16 -05003493 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3494 {
3495 if (unformat (input, "hash-buckets %d", &tmp))
3496 nbuckets = tmp;
3497 else if (unformat (input, "heap-size %dm", &tmp))
3498 heapsize = ((u64) tmp) << 20;
3499 else if (unformat (input, "heap-size %dM", &tmp))
3500 heapsize = ((u64) tmp) << 20;
3501 else if (unformat (input, "heap-size %dg", &tmp))
3502 heapsize = ((u64) tmp) << 30;
3503 else if (unformat (input, "heap-size %dG", &tmp))
3504 heapsize = ((u64) tmp) << 30;
3505 else
3506 return clib_error_return (0, "unknown input '%U'",
3507 format_unformat_error, input);
3508 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003509
3510 im->lookup_table_nbuckets = nbuckets;
3511 im->lookup_table_size = heapsize;
3512
3513 return 0;
3514}
3515
3516VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003517
3518/*
3519 * fd.io coding-style-patch-verification: ON
3520 *
3521 * Local Variables:
3522 * eval: (c-set-style "gnu")
3523 * End:
3524 */