blob: ecc3bd2cc6ee27a2aac797c420d00d07571f9bc4 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
AkshayaNadahallied4a2fd2016-08-09 13:38:04 +05302 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ip/ip6_forward.c: IP v6 forwarding
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vnet/vnet.h>
41#include <vnet/ip/ip.h>
Dave Barachd7cb1b52016-12-09 09:52:16 -050042#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
44#include <vppinfra/cache.h>
AkshayaNadahalli0f438df2017-02-10 10:54:16 +053045#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010046#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000047#include <vnet/mfib/ip6_mfib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010048#include <vnet/dpo/load_balance.h>
49#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070050
51#include <vppinfra/bihash_template.c>
52
AkshayaNadahallifdd81af2016-12-01 16:33:51 +053053/* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
54#define OI_DECAP 0x80000000
55
Billy McFall0683c9c2016-10-13 08:27:31 -040056/**
57 * @file
58 * @brief IPv6 Forwarding.
59 *
60 * This file contains the source code for IPv6 forwarding.
61 */
62
Pierre Pfister0febaf12016-06-08 12:23:21 +010063void
64ip6_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050065 vlib_node_runtime_t * node,
66 vlib_frame_t * frame,
67 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010068
Damjan Marionaca64c92016-04-13 09:48:56 +020069always_inline uword
70ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050071 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
Dave Barachd7cb1b52016-12-09 09:52:16 -050073 ip6_main_t *im = &ip6_main;
74 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
75 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070076 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -050077 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
79 from = vlib_frame_vector_args (frame);
80 n_left_from = frame->n_vectors;
81 next = node->cached_next_index;
82
83 while (n_left_from > 0)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
87 while (n_left_from >= 4 && n_left_to_next >= 2)
88 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050089 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010090 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050092 ip6_header_t *ip0, *ip1;
93 ip6_address_t *dst_addr0, *dst_addr1;
94 u32 fib_index0, fib_index1;
95 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010096 const dpo_id_t *dpo0, *dpo1;
97 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 /* Prefetch next iteration. */
100 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102
103 p2 = vlib_get_buffer (vm, from[2]);
104 p3 = vlib_get_buffer (vm, from[3]);
105
106 vlib_prefetch_buffer_header (p2, LOAD);
107 vlib_prefetch_buffer_header (p3, LOAD);
108 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
109 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
110 }
111
112 pi0 = to_next[0] = from[0];
113 pi1 = to_next[1] = from[1];
114
115 p0 = vlib_get_buffer (vm, pi0);
116 p1 = vlib_get_buffer (vm, pi1);
117
118 ip0 = vlib_buffer_get_current (p0);
119 ip1 = vlib_buffer_get_current (p1);
120
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121 dst_addr0 = &ip0->dst_address;
122 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200123
Dave Barachd7cb1b52016-12-09 09:52:16 -0500124 fib_index0 =
125 vec_elt (im->fib_index_by_sw_if_index,
126 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
127 fib_index1 =
128 vec_elt (im->fib_index_by_sw_if_index,
129 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barachd7cb1b52016-12-09 09:52:16 -0500131 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
132 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
133 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
134 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100136 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
137 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100139 lb0 = load_balance_get (lbi0);
140 lb1 = load_balance_get (lbi1);
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);
149 }
150 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
151 {
152 flow_hash_config1 = lb1->lb_hash_config;
153 vnet_buffer (p1)->ip.flow_hash =
154 ip6_compute_flow_hash (ip1, flow_hash_config1);
155 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100157 ASSERT (lb0->lb_n_buckets > 0);
158 ASSERT (lb1->lb_n_buckets > 0);
159 ASSERT (is_pow2 (lb0->lb_n_buckets));
160 ASSERT (is_pow2 (lb1->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500161 dpo0 = load_balance_get_bucket_i (lb0,
162 (vnet_buffer (p0)->ip.flow_hash &
163 lb0->lb_n_buckets_minus_1));
164 dpo1 = load_balance_get_bucket_i (lb1,
165 (vnet_buffer (p1)->ip.flow_hash &
166 lb1->lb_n_buckets_minus_1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100168 next0 = dpo0->dpoi_next_node;
169 next1 = dpo1->dpoi_next_node;
170
171 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500172 if (PREDICT_FALSE
173 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100174 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500175 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100176 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
177 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500178 if (PREDICT_FALSE
179 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100180 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100182 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
183 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100184 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
185 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186
Dave Barach75fc8542016-10-11 16:16:02 -0400187 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500188 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400189 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500190 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
192 from += 2;
193 to_next += 2;
194 n_left_to_next -= 2;
195 n_left_from -= 2;
196
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500199 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 switch (wrong_next)
201 {
202 case 1:
203 /* A B A */
204 to_next[-2] = pi1;
205 to_next -= 1;
206 n_left_to_next += 1;
207 vlib_set_next_frame_buffer (vm, node, next0, pi0);
208 break;
209
210 case 2:
211 /* A A B */
212 to_next -= 1;
213 n_left_to_next += 1;
214 vlib_set_next_frame_buffer (vm, node, next1, pi1);
215 break;
216
217 case 3:
218 /* A B C */
219 to_next -= 2;
220 n_left_to_next += 2;
221 vlib_set_next_frame_buffer (vm, node, next0, pi0);
222 vlib_set_next_frame_buffer (vm, node, next1, pi1);
223 if (next0 == next1)
224 {
225 /* A B B */
226 vlib_put_next_frame (vm, node, next, n_left_to_next);
227 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500228 vlib_get_next_frame (vm, node, next, to_next,
229 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230 }
231 }
232 }
233 }
Dave Barach75fc8542016-10-11 16:16:02 -0400234
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235 while (n_left_from > 0 && n_left_to_next > 0)
236 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 vlib_buffer_t *p0;
238 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500241 load_balance_t *lb0;
242 ip6_address_t *dst_addr0;
243 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100244 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245
246 pi0 = from[0];
247 to_next[0] = pi0;
248
249 p0 = vlib_get_buffer (vm, pi0);
250
251 ip0 = vlib_buffer_get_current (p0);
252
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100253 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200254
Dave Barachd7cb1b52016-12-09 09:52:16 -0500255 fib_index0 =
256 vec_elt (im->fib_index_by_sw_if_index,
257 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
258 fib_index0 =
259 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
260 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
Dave Barachd7cb1b52016-12-09 09:52:16 -0500262 flow_hash_config0 = ip6_fib_get (fib_index0)->flow_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100264 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100266 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Dave Barachd7cb1b52016-12-09 09:52:16 -0500268 vnet_buffer (p0)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269
Dave Barachd7cb1b52016-12-09 09:52:16 -0500270 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
271 {
272 flow_hash_config0 = lb0->lb_hash_config;
273 vnet_buffer (p0)->ip.flow_hash =
274 ip6_compute_flow_hash (ip0, flow_hash_config0);
275 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277 ASSERT (lb0->lb_n_buckets > 0);
278 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500279 dpo0 = load_balance_get_bucket_i (lb0,
280 (vnet_buffer (p0)->ip.flow_hash &
281 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283
Shwetha57fc8542016-09-27 08:04:05 +0100284 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500285 if (PREDICT_FALSE
286 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100287 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500288 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100289 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
290 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100291 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292
Dave Barach75fc8542016-10-11 16:16:02 -0400293 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500294 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295
296 from += 1;
297 to_next += 1;
298 n_left_to_next -= 1;
299 n_left_from -= 1;
300
301 if (PREDICT_FALSE (next0 != next))
302 {
303 n_left_to_next += 1;
304 vlib_put_next_frame (vm, node, next, n_left_to_next);
305 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500306 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307 to_next[0] = pi0;
308 to_next += 1;
309 n_left_to_next -= 1;
310 }
311 }
312
313 vlib_put_next_frame (vm, node, next, n_left_to_next);
314 }
315
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100316 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500317 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100318
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319 return frame->n_vectors;
320}
321
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322static void
323ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
324 ip6_main_t * im, u32 fib_index,
325 ip_interface_address_t * a)
326{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500327 ip_lookup_main_t *lm = &im->lookup_main;
328 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500330 .fp_len = a->address_length,
331 .fp_proto = FIB_PROTOCOL_IP6,
332 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100333 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700334
335 a->neighbor_probe_adj_index = ~0;
336 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500337 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100338 fib_node_index_t fei;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
Dave Barachd7cb1b52016-12-09 09:52:16 -0500340 fei = fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_ATTACHED), FIB_PROTOCOL_IP6, NULL, /* No next-hop address */
341 sw_if_index, ~0, // invalid FIB index
342 1, NULL, // no label stack
343 FIB_ROUTE_PATH_FLAG_NONE);
344 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
345 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100347 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500349 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100350 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500351 lm->classify_table_index_by_sw_if_index[sw_if_index];
352 if (classify_table_index != (u32) ~ 0)
353 {
354 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100355
Dave Barachd7cb1b52016-12-09 09:52:16 -0500356 dpo_set (&dpo,
357 DPO_CLASSIFY,
358 DPO_PROTO_IP6,
359 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100360
Dave Barachd7cb1b52016-12-09 09:52:16 -0500361 fib_table_entry_special_dpo_add (fib_index,
362 &pfx,
363 FIB_SOURCE_CLASSIFY,
364 FIB_ENTRY_FLAG_NONE, &dpo);
365 dpo_reset (&dpo);
366 }
367 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100368
Dave Barachd7cb1b52016-12-09 09:52:16 -0500369 fib_table_entry_update_one_path (fib_index, &pfx, FIB_SOURCE_INTERFACE, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL), FIB_PROTOCOL_IP6, &pfx.fp_addr, sw_if_index, ~0, // invalid FIB index
370 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371}
372
373static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100374ip6_del_interface_routes (ip6_main_t * im,
375 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500376 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500378 fib_prefix_t pfx = {
379 .fp_len = address_length,
380 .fp_proto = FIB_PROTOCOL_IP6,
381 .fp_addr.ip6 = *address,
382 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
Dave Barachd7cb1b52016-12-09 09:52:16 -0500384 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500386 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100387
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 }
389
Dave Barachd7cb1b52016-12-09 09:52:16 -0500390 pfx.fp_len = 128;
391 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392}
393
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100394void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500395ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100396{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500397 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100399 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100401 /*
402 * enable/disable only on the 1<->0 transition
403 */
404 if (is_enable)
405 {
406 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500407 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100408 }
409 else
410 {
Neale Ranns75152282017-01-09 01:00:45 -0800411 /* The ref count is 0 when an address is removed from an interface that has
412 * no address - this is not a ciritical error */
413 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
414 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500415 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100416 }
417
Damjan Marion8b3191e2016-11-09 19:54:20 +0100418 vnet_feature_enable_disable ("ip6-unicast", "ip6-lookup", sw_if_index,
419 is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100420
Neale Ranns32e1c012016-11-22 17:07:28 +0000421 vnet_feature_enable_disable ("ip6-multicast", "ip6-mfib-forward-lookup",
422 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100424}
425
Neale Rannsdf089a82016-10-02 16:39:06 +0100426/* get first interface address */
427ip6_address_t *
Neale Ranns6cfc39c2017-02-14 01:44:25 -0800428ip6_interface_first_address (ip6_main_t * im, u32 sw_if_index)
Neale Rannsdf089a82016-10-02 16:39:06 +0100429{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500430 ip_lookup_main_t *lm = &im->lookup_main;
431 ip_interface_address_t *ia = 0;
432 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100433
Dave Barachd7cb1b52016-12-09 09:52:16 -0500434 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100435 foreach_ip_interface_address (lm, ia, sw_if_index,
436 1 /* honor unnumbered */,
437 ({
438 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
439 result = a;
440 break;
441 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500442 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100443 return result;
444}
445
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446clib_error_t *
447ip6_add_del_interface_address (vlib_main_t * vm,
448 u32 sw_if_index,
449 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500450 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 vnet_main_t *vnm = vnet_get_main ();
453 ip6_main_t *im = &ip6_main;
454 ip_lookup_main_t *lm = &im->lookup_main;
455 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500457 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458
459 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000460 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
461
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 ip6_addr_fib_init (&ip6_af, address,
463 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
464 vec_add1 (addr_fib, ip6_af);
465
466 {
467 uword elts_before = pool_elts (lm->if_address_pool);
468
469 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500470 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 if (error)
472 goto done;
473
474 /* Pool did not grow: add duplicate address. */
475 if (elts_before == pool_elts (lm->if_address_pool))
476 goto done;
477 }
478
Dave Barachd7cb1b52016-12-09 09:52:16 -0500479 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000480
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100481 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100483 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500484 ip6_add_interface_routes (vnm, sw_if_index,
485 im, ip6_af.fib_index,
486 pool_elt_at_index (lm->if_address_pool,
487 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488
489 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 vec_foreach (cb, im->add_del_interface_address_callbacks)
492 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500493 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 }
495
Dave Barachd7cb1b52016-12-09 09:52:16 -0500496done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497 vec_free (addr_fib);
498 return error;
499}
500
501clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500502ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500504 ip6_main_t *im = &ip6_main;
505 ip_interface_address_t *ia;
506 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507 u32 is_admin_up, fib_index;
508
509 /* Fill in lookup tables with default table (0). */
510 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
511
Dave Barachd7cb1b52016-12-09 09:52:16 -0500512 vec_validate_init_empty (im->
513 lookup_main.if_address_pool_index_by_sw_if_index,
514 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
517
518 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
519
Dave Barachd7cb1b52016-12-09 09:52:16 -0500520 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400521 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522 0 /* honor unnumbered */,
523 ({
524 a = ip_interface_address_get_address (&im->lookup_main, ia);
525 if (is_admin_up)
526 ip6_add_interface_routes (vnm, sw_if_index,
527 im, fib_index,
528 ia);
529 else
530 ip6_del_interface_routes (im, fib_index,
531 a, ia->address_length);
532 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500533 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534
535 return 0;
536}
537
538VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
539
Dave Barachd6534602016-06-14 18:38:02 -0400540/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500541/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100542VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
543{
544 .arc_name = "ip6-unicast",
545 .start_nodes = VNET_FEATURES ("ip6-input"),
546 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
547};
548
Dave Barachd7cb1b52016-12-09 09:52:16 -0500549VNET_FEATURE_INIT (ip6_flow_classify, static) =
550{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100551 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700552 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100553 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700554};
555
Dave Barachd7cb1b52016-12-09 09:52:16 -0500556VNET_FEATURE_INIT (ip6_inacl, static) =
557{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100558 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400559 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100560 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400561};
562
Dave Barachd7cb1b52016-12-09 09:52:16 -0500563VNET_FEATURE_INIT (ip6_policer_classify, static) =
564{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100565 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700566 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100567 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700568};
569
Dave Barachd7cb1b52016-12-09 09:52:16 -0500570VNET_FEATURE_INIT (ip6_ipsec, static) =
571{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100572 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400573 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100574 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400575};
576
Dave Barachd7cb1b52016-12-09 09:52:16 -0500577VNET_FEATURE_INIT (ip6_l2tp, static) =
578{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100579 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400580 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100581 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400582};
583
Dave Barachd7cb1b52016-12-09 09:52:16 -0500584VNET_FEATURE_INIT (ip6_vpath, static) =
585{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100586 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400587 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500588 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
589};
590
591VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
592{
593 .arc_name = "ip6-unicast",
594 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100595 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400596};
597
Dave Barachd7cb1b52016-12-09 09:52:16 -0500598VNET_FEATURE_INIT (ip6_lookup, static) =
599{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100600 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400601 .node_name = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100602 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400603};
604
Dave Barachd7cb1b52016-12-09 09:52:16 -0500605VNET_FEATURE_INIT (ip6_drop, static) =
606{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100607 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100608 .node_name = "ip6-drop",
609 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100610};
611
Dave Barachd6534602016-06-14 18:38:02 -0400612/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100613VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
614{
615 .arc_name = "ip6-multicast",
616 .start_nodes = VNET_FEATURES ("ip6-input"),
617 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
618};
619
620VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
621 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400622 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000623 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400624};
625
Damjan Marion8b3191e2016-11-09 19:54:20 +0100626VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
627 .arc_name = "ip6-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +0000628 .node_name = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100629 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400630};
631
Damjan Marion8b3191e2016-11-09 19:54:20 +0100632VNET_FEATURE_INIT (ip6_drop_mc, static) = {
633 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100634 .node_name = "ip6-drop",
635 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100636};
Dave Barach5331c722016-08-17 11:54:30 -0400637
638/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100639VNET_FEATURE_ARC_INIT (ip6_output, static) =
640{
641 .arc_name = "ip6-output",
642 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
643 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400644};
645
Matus Fabian08a6f012016-11-15 06:08:51 -0800646VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
647 .arc_name = "ip6-output",
648 .node_name = "ipsec-output-ip6",
649 .runs_before = VNET_FEATURES ("interface-output"),
650};
651
Damjan Marion8b3191e2016-11-09 19:54:20 +0100652VNET_FEATURE_INIT (ip6_interface_output, static) = {
653 .arc_name = "ip6-output",
654 .node_name = "interface-output",
655 .runs_before = 0, /* not before any other features */
656};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500657/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400658
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500660ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100662 vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
663 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664
Damjan Marion8b3191e2016-11-09 19:54:20 +0100665 vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
666 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667
Damjan Marion8b3191e2016-11-09 19:54:20 +0100668 vnet_feature_enable_disable ("ip6-output", "interface-output", sw_if_index,
669 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671 return /* no error */ 0;
672}
673
674VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
675
Damjan Marionaca64c92016-04-13 09:48:56 +0200676static uword
677ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500678 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200679{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100680 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200681}
682
Dave Barachd7cb1b52016-12-09 09:52:16 -0500683static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100684
Dave Barachd7cb1b52016-12-09 09:52:16 -0500685/* *INDENT-OFF* */
686VLIB_REGISTER_NODE (ip6_lookup_node) =
687{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688 .function = ip6_lookup,
689 .name = "ip6-lookup",
690 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100691 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200692 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200693 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500695/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696
Dave Barachd7cb1b52016-12-09 09:52:16 -0500697VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200698
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100699always_inline uword
700ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500701 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200702{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500703 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
704 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706 u32 cpu_index = os_get_cpu_number ();
707 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100708
709 from = vlib_frame_vector_args (frame);
710 n_left_from = frame->n_vectors;
711 next = node->cached_next_index;
712
713 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500714 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100715
716 while (n_left_from > 0)
717 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500718 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100719
Dave Barach75fc8542016-10-11 16:16:02 -0400720
Neale Ranns2be95c12016-11-19 13:50:04 +0000721 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500722 {
723 ip_lookup_next_t next0, next1;
724 const load_balance_t *lb0, *lb1;
725 vlib_buffer_t *p0, *p1;
726 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
727 const ip6_header_t *ip0, *ip1;
728 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000729
Dave Barachd7cb1b52016-12-09 09:52:16 -0500730 /* Prefetch next iteration. */
731 {
732 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000733
Dave Barachd7cb1b52016-12-09 09:52:16 -0500734 p2 = vlib_get_buffer (vm, from[2]);
735 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000736
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737 vlib_prefetch_buffer_header (p2, STORE);
738 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000739
Dave Barachd7cb1b52016-12-09 09:52:16 -0500740 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
741 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
742 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000743
Dave Barachd7cb1b52016-12-09 09:52:16 -0500744 pi0 = to_next[0] = from[0];
745 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000746
Dave Barachd7cb1b52016-12-09 09:52:16 -0500747 from += 2;
748 n_left_from -= 2;
749 to_next += 2;
750 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000751
Dave Barachd7cb1b52016-12-09 09:52:16 -0500752 p0 = vlib_get_buffer (vm, pi0);
753 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000754
Dave Barachd7cb1b52016-12-09 09:52:16 -0500755 ip0 = vlib_buffer_get_current (p0);
756 ip1 = vlib_buffer_get_current (p1);
757 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
758 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000759
Dave Barachd7cb1b52016-12-09 09:52:16 -0500760 lb0 = load_balance_get (lbi0);
761 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000762
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 /*
764 * this node is for via FIBs we can re-use the hash value from the
765 * to node if present.
766 * We don't want to use the same hash value at each level in the recursion
767 * graph as that would lead to polarisation
768 */
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000769 hc0 = hc1 = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000770
Dave Barachd7cb1b52016-12-09 09:52:16 -0500771 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
772 {
773 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
774 {
775 hc0 = vnet_buffer (p0)->ip.flow_hash =
776 vnet_buffer (p0)->ip.flow_hash >> 1;
777 }
778 else
779 {
780 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000781 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 }
783 }
784 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
785 {
786 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
787 {
788 hc1 = vnet_buffer (p1)->ip.flow_hash =
789 vnet_buffer (p1)->ip.flow_hash >> 1;
790 }
791 else
792 {
793 hc1 = vnet_buffer (p1)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000794 ip6_compute_flow_hash (ip1, lb1->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500795 }
796 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000797
Dave Barachd7cb1b52016-12-09 09:52:16 -0500798 dpo0 =
799 load_balance_get_bucket_i (lb0,
800 hc0 & (lb0->lb_n_buckets_minus_1));
801 dpo1 =
802 load_balance_get_bucket_i (lb1,
803 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000804
Dave Barachd7cb1b52016-12-09 09:52:16 -0500805 next0 = dpo0->dpoi_next_node;
806 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000807
Dave Barachd7cb1b52016-12-09 09:52:16 -0500808 /* Only process the HBH Option Header if explicitly configured to do so */
809 if (PREDICT_FALSE
810 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
811 {
812 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
813 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
814 }
815 /* Only process the HBH Option Header if explicitly configured to do so */
816 if (PREDICT_FALSE
817 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
818 {
819 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
820 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
821 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000822
Dave Barachd7cb1b52016-12-09 09:52:16 -0500823 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
824 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000825
Dave Barachd7cb1b52016-12-09 09:52:16 -0500826 vlib_increment_combined_counter
827 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
828 vlib_increment_combined_counter
829 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000830
Dave Barachd7cb1b52016-12-09 09:52:16 -0500831 vlib_validate_buffer_enqueue_x2 (vm, node, next,
832 to_next, n_left_to_next,
833 pi0, pi1, next0, next1);
834 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000835
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100836 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500837 {
838 ip_lookup_next_t next0;
839 const load_balance_t *lb0;
840 vlib_buffer_t *p0;
841 u32 pi0, lbi0, hc0;
842 const ip6_header_t *ip0;
843 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100844
Dave Barachd7cb1b52016-12-09 09:52:16 -0500845 pi0 = from[0];
846 to_next[0] = pi0;
847 from += 1;
848 to_next += 1;
849 n_left_to_next -= 1;
850 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100851
Dave Barachd7cb1b52016-12-09 09:52:16 -0500852 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100853
Dave Barachd7cb1b52016-12-09 09:52:16 -0500854 ip0 = vlib_buffer_get_current (p0);
855 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100856
Dave Barachd7cb1b52016-12-09 09:52:16 -0500857 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100858
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000859 hc0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500860 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
861 {
862 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
863 {
864 hc0 = vnet_buffer (p0)->ip.flow_hash =
865 vnet_buffer (p0)->ip.flow_hash >> 1;
866 }
867 else
868 {
869 hc0 = vnet_buffer (p0)->ip.flow_hash =
AkshayaNadahalli153b8712017-03-06 18:22:29 +0000870 ip6_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500871 }
872 }
873 dpo0 =
874 load_balance_get_bucket_i (lb0,
875 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100876
Dave Barachd7cb1b52016-12-09 09:52:16 -0500877 next0 = dpo0->dpoi_next_node;
878 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000879
Dave Barachd7cb1b52016-12-09 09:52:16 -0500880 /* Only process the HBH Option Header if explicitly configured to do so */
881 if (PREDICT_FALSE
882 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
883 {
884 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
885 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
886 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000887
Dave Barachd7cb1b52016-12-09 09:52:16 -0500888 vlib_increment_combined_counter
889 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100890
Dave Barachd7cb1b52016-12-09 09:52:16 -0500891 vlib_validate_buffer_enqueue_x1 (vm, node, next,
892 to_next, n_left_to_next,
893 pi0, next0);
894 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100895
896 vlib_put_next_frame (vm, node, next, n_left_to_next);
897 }
898
899 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200900}
901
Dave Barachd7cb1b52016-12-09 09:52:16 -0500902/* *INDENT-OFF* */
903VLIB_REGISTER_NODE (ip6_load_balance_node) =
904{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100905 .function = ip6_load_balance,
906 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200907 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200908 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100909 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200910};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500911/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200912
Dave Barachd7cb1b52016-12-09 09:52:16 -0500913VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200914
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915typedef struct
916{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700917 /* Adjacency taken. */
918 u32 adj_index;
919 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500920 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921
922 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500923 u8 packet_data[128 - 1 * sizeof (u32)];
924}
925ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926
John Lo2b81eb82017-01-30 13:12:10 -0500927u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500928format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100930 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
931 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500932 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100933 uword indent = format_get_indent (s);
934
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935 s = format (s, "%U%U",
936 format_white_space, indent,
937 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100938 return s;
939}
940
Dave Barachd7cb1b52016-12-09 09:52:16 -0500941static u8 *
942format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100943{
944 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
945 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947 uword indent = format_get_indent (s);
948
John Loac8146c2016-09-27 17:44:02 -0400949 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500950 t->fib_index, t->adj_index, t->flow_hash);
951 s = format (s, "\n%U%U",
952 format_white_space, indent,
953 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100954 return s;
955}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100956
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957
Dave Barachd7cb1b52016-12-09 09:52:16 -0500958static u8 *
959format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100960{
961 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
962 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500963 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100964 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700965
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100966 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500967 t->fib_index, t->adj_index, format_ip_adjacency,
968 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100969 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970 format_white_space, indent,
971 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -0400972 t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973 return s;
974}
975
976/* Common trace function for all ip6-forward next nodes. */
977void
978ip6_forward_next_trace (vlib_main_t * vm,
979 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500980 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500982 u32 *from, n_left;
983 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984
985 n_left = frame->n_vectors;
986 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100987
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988 while (n_left >= 4)
989 {
990 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500991 vlib_buffer_t *b0, *b1;
992 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993
994 /* Prefetch next iteration. */
995 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
996 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
997
998 bi0 = from[0];
999 bi1 = from[1];
1000
1001 b0 = vlib_get_buffer (vm, bi0);
1002 b1 = vlib_get_buffer (vm, bi1);
1003
1004 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1005 {
1006 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1007 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001008 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1009 t0->fib_index =
1010 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1011 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1012 vec_elt (im->fib_index_by_sw_if_index,
1013 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001014
Damjan Marionf1213b82016-03-13 02:22:06 +01001015 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001016 vlib_buffer_get_current (b0),
1017 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018 }
1019 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1020 {
1021 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1022 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001023 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1024 t1->fib_index =
1025 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1026 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1027 vec_elt (im->fib_index_by_sw_if_index,
1028 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001029
Damjan Marionf1213b82016-03-13 02:22:06 +01001030 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031 vlib_buffer_get_current (b1),
1032 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 }
1034 from += 2;
1035 n_left -= 2;
1036 }
1037
1038 while (n_left >= 1)
1039 {
1040 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001041 vlib_buffer_t *b0;
1042 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043
1044 bi0 = from[0];
1045
1046 b0 = vlib_get_buffer (vm, bi0);
1047
1048 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1049 {
1050 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1051 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001052 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1053 t0->fib_index =
1054 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1055 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1056 vec_elt (im->fib_index_by_sw_if_index,
1057 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001058
Damjan Marionf1213b82016-03-13 02:22:06 +01001059 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001060 vlib_buffer_get_current (b0),
1061 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 }
1063 from += 1;
1064 n_left -= 1;
1065 }
1066}
1067
1068static uword
1069ip6_drop_or_punt (vlib_main_t * vm,
1070 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001071 vlib_frame_t * frame, ip6_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001073 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 uword n_packets = frame->n_vectors;
1075
Dave Barachd7cb1b52016-12-09 09:52:16 -05001076 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 /* stride */ 1,
1078 n_packets,
1079 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001080 ip6_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081
1082 if (node->flags & VLIB_NODE_FLAG_TRACE)
1083 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1084
1085 return n_packets;
1086}
1087
1088static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001089ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1090{
1091 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1092}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093
1094static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001095ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1096{
1097 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1098}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099
Dave Barachd7cb1b52016-12-09 09:52:16 -05001100/* *INDENT-OFF* */
1101VLIB_REGISTER_NODE (ip6_drop_node, static) =
1102{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 .function = ip6_drop,
1104 .name = "ip6-drop",
1105 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001108 .next_nodes =
1109 {
1110 [0] = "error-drop",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001112/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
Dave Barachd7cb1b52016-12-09 09:52:16 -05001114VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001115
Dave Barachd7cb1b52016-12-09 09:52:16 -05001116/* *INDENT-OFF* */
1117VLIB_REGISTER_NODE (ip6_punt_node, static) =
1118{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 .function = ip6_punt,
1120 .name = "ip6-punt",
1121 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001124 .next_nodes =
1125 {
1126 [0] = "error-punt",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001128/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001129
Dave Barachd7cb1b52016-12-09 09:52:16 -05001130VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001131
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133u16
1134ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1135 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136{
1137 ip_csum_t sum0;
1138 u16 sum16, payload_length_host_byte_order;
1139 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001140 u32 headers_size = sizeof (ip0[0]);
1141 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142
Dave Barachd7cb1b52016-12-09 09:52:16 -05001143 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 *bogus_lengthp = 0;
1145
1146 /* Initialize checksum with ip header. */
1147 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1148 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1149 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001150
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1152 {
1153 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001154 clib_mem_unaligned (&ip0->
1155 src_address.as_uword[i],
1156 uword));
1157 sum0 =
1158 ip_csum_with_carry (sum0,
1159 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1160 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161 }
1162
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301163 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1164 * or UDP-Ping packets */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001165 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001167 u32 skip_bytes;
1168 ip6_hop_by_hop_ext_t *ext_hdr =
1169 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170
1171 /* validate really icmp6 next */
AkshayaNadahalli1b563522017-01-23 22:05:35 +05301172 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1173 || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
Dave Barachd7cb1b52016-12-09 09:52:16 -05001175 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1176 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001177
Dave Barachd7cb1b52016-12-09 09:52:16 -05001178 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001180 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
1182 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001183 if (p0 && n_this_buffer + headers_size > p0->current_length)
1184 n_this_buffer =
1185 p0->current_length >
1186 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001187 while (1)
1188 {
1189 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1190 n_bytes_left -= n_this_buffer;
1191 if (n_bytes_left == 0)
1192 break;
1193
1194 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001195 {
1196 *bogus_lengthp = 1;
1197 return 0xfefe;
1198 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 p0 = vlib_get_buffer (vm, p0->next_buffer);
1200 data_this_buffer = vlib_buffer_get_current (p0);
1201 n_this_buffer = p0->current_length;
1202 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203
Dave Barachd7cb1b52016-12-09 09:52:16 -05001204 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205
1206 return sum16;
1207}
1208
Dave Barachd7cb1b52016-12-09 09:52:16 -05001209u32
1210ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001212 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1213 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214 u16 sum16;
1215 int bogus_length;
1216
1217 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1218 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1219 || ip0->protocol == IP_PROTOCOL_ICMP6
1220 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001221 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001222
1223 udp0 = (void *) (ip0 + 1);
1224 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1225 {
1226 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1227 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1228 return p0->flags;
1229 }
1230
1231 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1232
1233 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1234 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1235
1236 return p0->flags;
1237}
1238
AkshayaNadahalli0f438df2017-02-10 10:54:16 +05301239/**
1240 * @brief returns number of links on which src is reachable.
1241 */
1242always_inline int
1243ip6_urpf_loose_check (ip6_main_t * im, vlib_buffer_t * b, ip6_header_t * i)
1244{
1245 const load_balance_t *lb0;
1246 index_t lbi;
1247
1248 lbi = ip6_fib_table_fwding_lookup_with_if_index (im,
1249 vnet_buffer
1250 (b)->sw_if_index[VLIB_RX],
1251 &i->src_address);
1252
1253 lb0 = load_balance_get (lbi);
1254
1255 return (fib_urpf_check_size (lb0->lb_urpf));
1256}
1257
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001259ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001260{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001261 ip6_main_t *im = &ip6_main;
1262 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001264 u32 *from, *to_next, n_left_from, n_left_to_next;
1265 vlib_node_runtime_t *error_node =
1266 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267
1268 from = vlib_frame_vector_args (frame);
1269 n_left_from = frame->n_vectors;
1270 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001271
Ed Warnickecb9cada2015-12-08 15:45:58 -07001272 if (node->flags & VLIB_NODE_FLAG_TRACE)
1273 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1274
1275 while (n_left_from > 0)
1276 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001277 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001278
1279 while (n_left_from >= 4 && n_left_to_next >= 2)
1280 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001281 vlib_buffer_t *p0, *p1;
1282 ip6_header_t *ip0, *ip1;
1283 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284 u32 pi0, ip_len0, udp_len0, flags0, next0;
1285 u32 pi1, ip_len1, udp_len1, flags1, next1;
1286 i32 len_diff0, len_diff1;
1287 u8 error0, type0, good_l4_checksum0;
1288 u8 error1, type1, good_l4_checksum1;
Shwethab78292e2016-09-13 11:51:00 +01001289 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001290
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291 pi0 = to_next[0] = from[0];
1292 pi1 = to_next[1] = from[1];
1293 from += 2;
1294 n_left_from -= 2;
1295 to_next += 2;
1296 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001297
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 p0 = vlib_get_buffer (vm, pi0);
1299 p1 = vlib_get_buffer (vm, pi1);
1300
1301 ip0 = vlib_buffer_get_current (p0);
1302 ip1 = vlib_buffer_get_current (p1);
1303
Filip Tehlarb601f222017-01-02 10:22:56 +01001304 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1305 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1306
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1308 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1309
1310 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1311 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1312
1313 flags0 = p0->flags;
1314 flags1 = p1->flags;
1315
1316 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1317 good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001318 len_diff0 = 0;
1319 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001320
Dave Barachd7cb1b52016-12-09 09:52:16 -05001321 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1322 IP_PROTOCOL_UDP,
1323 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001324 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001325 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001326 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001327 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1328 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001329 /* Verify UDP length. */
1330 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1331 udp_len0 = clib_net_to_host_u16 (udp0->length);
1332 len_diff0 = ip_len0 - udp_len0;
1333 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001334 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1335 IP_PROTOCOL_UDP,
1336 &udp_offset1)))
Shwethab78292e2016-09-13 11:51:00 +01001337 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001338 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001339 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001340 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1341 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001342 /* Verify UDP length. */
1343 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1344 udp_len1 = clib_net_to_host_u16 (udp1->length);
1345 len_diff1 = ip_len1 - udp_len1;
1346 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001347
1348 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1349 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1350
Ed Warnickecb9cada2015-12-08 15:45:58 -07001351 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1352 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1353
1354 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001355 && !good_l4_checksum0
1356 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357 {
1358 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1359 good_l4_checksum0 =
1360 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1361 }
1362 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001363 && !good_l4_checksum1
1364 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365 {
1366 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1367 good_l4_checksum1 =
1368 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1369 }
1370
1371 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1372
1373 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1374 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1375
Dave Barachd7cb1b52016-12-09 09:52:16 -05001376 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1377 IP6_ERROR_UDP_CHECKSUM);
1378 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1379 IP6_ERROR_ICMP_CHECKSUM);
1380 error0 =
1381 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1382 error1 =
1383 (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001384
1385 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001386 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001387 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1388 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001389 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301391 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001392 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001394 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1395 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001396 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301398 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001399 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400 }
1401
Dave Barachd7cb1b52016-12-09 09:52:16 -05001402 next0 =
1403 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1404 next1 =
1405 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001406
1407 p0->error = error_node->errors[error0];
1408 p1->error = error_node->errors[error1];
1409
1410 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1411 to_next, n_left_to_next,
1412 pi0, pi1, next0, next1);
1413 }
1414
1415 while (n_left_from > 0 && n_left_to_next > 0)
1416 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001417 vlib_buffer_t *p0;
1418 ip6_header_t *ip0;
1419 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001420 u32 pi0, ip_len0, udp_len0, flags0, next0;
1421 i32 len_diff0;
1422 u8 error0, type0, good_l4_checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001423 u32 udp_offset0;
Dave Barach75fc8542016-10-11 16:16:02 -04001424
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425 pi0 = to_next[0] = from[0];
1426 from += 1;
1427 n_left_from -= 1;
1428 to_next += 1;
1429 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001430
Ed Warnickecb9cada2015-12-08 15:45:58 -07001431 p0 = vlib_get_buffer (vm, pi0);
1432
1433 ip0 = vlib_buffer_get_current (p0);
1434
Filip Tehlarb601f222017-01-02 10:22:56 +01001435 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1436
Ed Warnickecb9cada2015-12-08 15:45:58 -07001437 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1438 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1439
1440 flags0 = p0->flags;
1441
1442 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001443 len_diff0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001444
Dave Barachd7cb1b52016-12-09 09:52:16 -05001445 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1446 IP_PROTOCOL_UDP,
1447 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001448 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001449 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001450 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001451 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1452 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001453 /* Verify UDP length. */
1454 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1455 udp_len0 = clib_net_to_host_u16 (udp0->length);
1456 len_diff0 = ip_len0 - udp_len0;
1457 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458
1459 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001460 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1461
1462 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001463 && !good_l4_checksum0
1464 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001465 {
1466 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1467 good_l4_checksum0 =
1468 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1469 }
1470
1471 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1472
1473 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1474
Dave Barachd7cb1b52016-12-09 09:52:16 -05001475 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1476 IP6_ERROR_UDP_CHECKSUM);
1477 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1478 IP6_ERROR_ICMP_CHECKSUM);
1479 error0 =
1480 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481
Dave Barachd7cb1b52016-12-09 09:52:16 -05001482 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001483 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1484 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001485 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001486 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301487 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001488 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001489 }
1490
Dave Barachd7cb1b52016-12-09 09:52:16 -05001491 next0 =
1492 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001493
1494 p0->error = error_node->errors[error0];
1495
1496 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1497 to_next, n_left_to_next,
1498 pi0, next0);
1499 }
Dave Barach75fc8542016-10-11 16:16:02 -04001500
Ed Warnickecb9cada2015-12-08 15:45:58 -07001501 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1502 }
1503
1504 return frame->n_vectors;
1505}
1506
Dave Barachd7cb1b52016-12-09 09:52:16 -05001507/* *INDENT-OFF* */
1508VLIB_REGISTER_NODE (ip6_local_node, static) =
1509{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001510 .function = ip6_local,
1511 .name = "ip6-local",
1512 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001513 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001514 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001515 .next_nodes =
1516 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001517 [IP_LOCAL_NEXT_DROP] = "error-drop",
1518 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001519 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1520 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1521 },
1522};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001523/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001524
Dave Barachd7cb1b52016-12-09 09:52:16 -05001525VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001526
Dave Barachd7cb1b52016-12-09 09:52:16 -05001527void
1528ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001529{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001530 vlib_main_t *vm = vlib_get_main ();
1531 ip6_main_t *im = &ip6_main;
1532 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001533
1534 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001535 lm->local_next_by_ip_protocol[protocol] =
1536 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001537}
1538
Dave Barachd7cb1b52016-12-09 09:52:16 -05001539typedef enum
1540{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001541 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001542 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001543 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1544} ip6_discover_neighbor_next_t;
1545
Dave Barachd7cb1b52016-12-09 09:52:16 -05001546typedef enum
1547{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1549 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001550 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001551} ip6_discover_neighbor_error_t;
1552
1553static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001554ip6_discover_neighbor_inline (vlib_main_t * vm,
1555 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001556 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001558 vnet_main_t *vnm = vnet_get_main ();
1559 ip6_main_t *im = &ip6_main;
1560 ip_lookup_main_t *lm = &im->lookup_main;
1561 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001562 uword n_left_from, n_left_to_next_drop;
1563 static f64 time_last_seed_change = -1e100;
1564 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001565 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001566 f64 time_now;
1567 int bogus_length;
1568
1569 if (node->flags & VLIB_NODE_FLAG_TRACE)
1570 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1571
1572 time_now = vlib_time_now (vm);
1573 if (time_now - time_last_seed_change > 1e-3)
1574 {
1575 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001576 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1577 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001578 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1579 hash_seeds[i] = r[i];
1580
1581 /* Mark all hash keys as been not-seen before. */
1582 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1583 hash_bitmap[i] = 0;
1584
1585 time_last_seed_change = time_now;
1586 }
1587
1588 from = vlib_frame_vector_args (frame);
1589 n_left_from = frame->n_vectors;
1590
1591 while (n_left_from > 0)
1592 {
1593 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1594 to_next_drop, n_left_to_next_drop);
1595
1596 while (n_left_from > 0 && n_left_to_next_drop > 0)
1597 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001598 vlib_buffer_t *p0;
1599 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001600 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1601 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001602 ip_adjacency_t *adj0;
1603 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604 u32 next0;
1605
1606 pi0 = from[0];
1607
1608 p0 = vlib_get_buffer (vm, pi0);
1609
1610 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1611
1612 ip0 = vlib_buffer_get_current (p0);
1613
1614 adj0 = ip_get_adjacency (lm, adj_index0);
1615
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001616 if (!is_glean)
1617 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001618 ip0->dst_address.as_u64[0] =
1619 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1620 ip0->dst_address.as_u64[1] =
1621 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001622 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001623
Ed Warnickecb9cada2015-12-08 15:45:58 -07001624 a0 = hash_seeds[0];
1625 b0 = hash_seeds[1];
1626 c0 = hash_seeds[2];
1627
1628 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1629 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1630
1631 a0 ^= sw_if_index0;
1632 b0 ^= ip0->dst_address.as_u32[0];
1633 c0 ^= ip0->dst_address.as_u32[1];
1634
1635 hash_v3_mix32 (a0, b0, c0);
1636
1637 b0 ^= ip0->dst_address.as_u32[2];
1638 c0 ^= ip0->dst_address.as_u32[3];
1639
1640 hash_v3_finalize32 (a0, b0, c0);
1641
1642 c0 &= BITS (hash_bitmap) - 1;
1643 c0 = c0 / BITS (uword);
1644 m0 = (uword) 1 << (c0 % BITS (uword));
1645
1646 bm0 = hash_bitmap[c0];
1647 drop0 = (bm0 & m0) != 0;
1648
1649 /* Mark it as seen. */
1650 hash_bitmap[c0] = bm0 | m0;
1651
1652 from += 1;
1653 n_left_from -= 1;
1654 to_next_drop[0] = pi0;
1655 to_next_drop += 1;
1656 n_left_to_next_drop -= 1;
1657
Dave Barachd7cb1b52016-12-09 09:52:16 -05001658 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001659
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660 /* If the interface is link-down, drop the pkt */
1661 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1662 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663
Dave Barach75fc8542016-10-11 16:16:02 -04001664 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001665 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1666 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001667 if (drop0)
1668 continue;
1669
Neale Rannsb80c5362016-10-08 13:03:40 +01001670 /*
1671 * the adj has been updated to a rewrite but the node the DPO that got
1672 * us here hasn't - yet. no big deal. we'll drop while we wait.
1673 */
1674 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1675 continue;
1676
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677 {
1678 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001679 icmp6_neighbor_solicitation_header_t *h0;
1680 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001681
Dave Barach75fc8542016-10-11 16:16:02 -04001682 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001683 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001684
Dave Barach75fc8542016-10-11 16:16:02 -04001685 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001686 * Build ethernet header.
1687 * Choose source address based on destination lookup
1688 * adjacency.
1689 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001690 if (ip6_src_address_for_packet (lm,
1691 sw_if_index0,
1692 &h0->ip.src_address))
1693 {
1694 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001695 p0->error =
1696 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1697 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001698 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001699 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001700
Dave Barach75fc8542016-10-11 16:16:02 -04001701 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 * Destination address is a solicited node multicast address.
1703 * We need to fill in
1704 * the low 24 bits with low 24 bits of target's address.
1705 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001706 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1707 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1708 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1709
1710 h0->neighbor.target_address = ip0->dst_address;
1711
Dave Barach75fc8542016-10-11 16:16:02 -04001712 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001713 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001714
Dave Barachd7cb1b52016-12-09 09:52:16 -05001715 /* $$$$ appears we need this; why is the checksum non-zero? */
1716 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001717 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001718 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1719 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001720
Dave Barachd7cb1b52016-12-09 09:52:16 -05001721 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001722
1723 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1724 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001725 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001726 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001727
1728 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001729 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001730 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1731
John Lod1f5d042016-04-12 18:20:39 -04001732 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733
1734 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1735 }
1736 }
1737
Dave Barach75fc8542016-10-11 16:16:02 -04001738 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001739 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001740 }
1741
1742 return frame->n_vectors;
1743}
1744
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001745static uword
1746ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001747 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001748{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001750}
1751
1752static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001753ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001754{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001755 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001756}
1757
Dave Barachd7cb1b52016-12-09 09:52:16 -05001758static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001759 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001760 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001761 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1762 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001763};
1764
Dave Barachd7cb1b52016-12-09 09:52:16 -05001765/* *INDENT-OFF* */
1766VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1767{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768 .function = ip6_discover_neighbor,
1769 .name = "ip6-discover-neighbor",
1770 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001771 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001772 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1773 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001774 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001775 .next_nodes =
1776 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001777 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001778 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001779 },
1780};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001781/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782
Dave Barachd7cb1b52016-12-09 09:52:16 -05001783/* *INDENT-OFF* */
1784VLIB_REGISTER_NODE (ip6_glean_node) =
1785{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001786 .function = ip6_glean,
1787 .name = "ip6-glean",
1788 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001789 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001790 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1791 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001792 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001793 .next_nodes =
1794 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001795 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1796 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1797 },
1798};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001800
Ed Warnickecb9cada2015-12-08 15:45:58 -07001801clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001802ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1803{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001804 vnet_main_t *vnm = vnet_get_main ();
1805 ip6_main_t *im = &ip6_main;
1806 icmp6_neighbor_solicitation_header_t *h;
1807 ip6_address_t *src;
1808 ip_interface_address_t *ia;
1809 ip_adjacency_t *adj;
1810 vnet_hw_interface_t *hi;
1811 vnet_sw_interface_t *si;
1812 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813 u32 bi = 0;
1814 int bogus_length;
1815
1816 si = vnet_get_sw_interface (vnm, sw_if_index);
1817
1818 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1819 {
1820 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001821 format_ip6_address, dst,
1822 format_vnet_sw_if_index_name, vnm,
1823 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 }
1825
Dave Barachd7cb1b52016-12-09 09:52:16 -05001826 src =
1827 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1828 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001829 {
1830 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001831 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001832 (0, "no matching interface address for destination %U (interface %U)",
1833 format_ip6_address, dst,
1834 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001835 }
1836
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837 h =
1838 vlib_packet_template_get_packet (vm,
1839 &im->discover_neighbor_packet_template,
1840 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001841
1842 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1843
1844 /* Destination address is a solicited node multicast address. We need to fill in
1845 the low 24 bits with low 24 bits of target's address. */
1846 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1847 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1848 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1849
1850 h->ip.src_address = src[0];
1851 h->neighbor.target_address = dst[0];
1852
Dave Barachd7cb1b52016-12-09 09:52:16 -05001853 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1854 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855
Dave Barach75fc8542016-10-11 16:16:02 -04001856 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001857 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001858 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001859
1860 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001861 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1862 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863
1864 /* Add encapsulation string for software interface (e.g. ethernet header). */
1865 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
1866 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1867 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1868
1869 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001870 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1871 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001872 to_next[0] = bi;
1873 f->n_vectors = 1;
1874 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1875 }
1876
1877 return /* no error */ 0;
1878}
1879
Dave Barachd7cb1b52016-12-09 09:52:16 -05001880typedef enum
1881{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001882 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001883 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001884} ip6_rewrite_next_t;
1885
1886always_inline uword
1887ip6_rewrite_inline (vlib_main_t * vm,
1888 vlib_node_runtime_t * node,
Neale Ranns9c6a6132017-02-21 05:33:14 -08001889 vlib_frame_t * frame,
1890 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001891{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001892 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1893 u32 *from = vlib_frame_vector_args (frame);
1894 u32 n_left_from, n_left_to_next, *to_next, next_index;
1895 vlib_node_runtime_t *error_node =
1896 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001897
1898 n_left_from = frame->n_vectors;
1899 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001900 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04001901
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902 while (n_left_from > 0)
1903 {
1904 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1905
1906 while (n_left_from >= 4 && n_left_to_next >= 2)
1907 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001908 ip_adjacency_t *adj0, *adj1;
1909 vlib_buffer_t *p0, *p1;
1910 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001911 u32 pi0, rw_len0, next0, error0, adj_index0;
1912 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001913 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001914
Ed Warnickecb9cada2015-12-08 15:45:58 -07001915 /* Prefetch next iteration. */
1916 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001917 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001918
1919 p2 = vlib_get_buffer (vm, from[2]);
1920 p3 = vlib_get_buffer (vm, from[3]);
1921
1922 vlib_prefetch_buffer_header (p2, LOAD);
1923 vlib_prefetch_buffer_header (p3, LOAD);
1924
1925 CLIB_PREFETCH (p2->pre_data, 32, STORE);
1926 CLIB_PREFETCH (p3->pre_data, 32, STORE);
1927
1928 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1929 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1930 }
1931
1932 pi0 = to_next[0] = from[0];
1933 pi1 = to_next[1] = from[1];
1934
1935 from += 2;
1936 n_left_from -= 2;
1937 to_next += 2;
1938 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001939
Ed Warnickecb9cada2015-12-08 15:45:58 -07001940 p0 = vlib_get_buffer (vm, pi0);
1941 p1 = vlib_get_buffer (vm, pi1);
1942
Neale Rannsf06aea52016-11-29 06:51:37 -08001943 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1944 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001945
Dave Barachd7cb1b52016-12-09 09:52:16 -05001946 /* We should never rewrite a pkt using the MISS adjacency */
1947 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001948
1949 ip0 = vlib_buffer_get_current (p0);
1950 ip1 = vlib_buffer_get_current (p1);
1951
1952 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001953 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001954
Dave Barachd7cb1b52016-12-09 09:52:16 -05001955 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001957 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001958
1959 /* Input node should have reject packets with hop limit 0. */
1960 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001961
1962 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001963
1964 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001965
Dave Barachd7cb1b52016-12-09 09:52:16 -05001966 /*
1967 * If the hop count drops below 1 when forwarding, generate
1968 * an ICMP response.
1969 */
1970 if (PREDICT_FALSE (hop_limit0 <= 0))
1971 {
1972 error0 = IP6_ERROR_TIME_EXPIRED;
1973 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1974 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1975 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1976 ICMP6_time_exceeded_ttl_exceeded_in_transit,
1977 0);
1978 }
Neale Rannsf06aea52016-11-29 06:51:37 -08001979 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001980 else
1981 {
1982 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
1983 }
1984 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
1985 {
Neale Rannsf06aea52016-11-29 06:51:37 -08001986 i32 hop_limit1 = ip1->hop_limit;
1987
1988 /* Input node should have reject packets with hop limit 0. */
1989 ASSERT (ip1->hop_limit > 0);
1990
1991 hop_limit1 -= 1;
1992
1993 ip1->hop_limit = hop_limit1;
1994
Dave Barachd7cb1b52016-12-09 09:52:16 -05001995 /*
1996 * If the hop count drops below 1 when forwarding, generate
1997 * an ICMP response.
1998 */
1999 if (PREDICT_FALSE (hop_limit1 <= 0))
2000 {
2001 error1 = IP6_ERROR_TIME_EXPIRED;
2002 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2003 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2004 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2005 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2006 0);
2007 }
2008 }
2009 else
2010 {
2011 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2012 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013 adj0 = ip_get_adjacency (lm, adj_index0);
2014 adj1 = ip_get_adjacency (lm, adj_index1);
2015
Ed Warnickecb9cada2015-12-08 15:45:58 -07002016 rw_len0 = adj0[0].rewrite_header.data_bytes;
2017 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002018 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2019 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002020
Neale Ranns9c6a6132017-02-21 05:33:14 -08002021 if (do_counters)
2022 {
2023 vlib_increment_combined_counter
2024 (&adjacency_counters,
2025 cpu_index, adj_index0, 1,
2026 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2027 vlib_increment_combined_counter
2028 (&adjacency_counters,
2029 cpu_index, adj_index1, 1,
2030 vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2031 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002032
2033 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002034 error0 =
2035 (vlib_buffer_length_in_chain (vm, p0) >
2036 adj0[0].
2037 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2038 error0);
2039 error1 =
2040 (vlib_buffer_length_in_chain (vm, p1) >
2041 adj1[0].
2042 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2043 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044
Dave Barachd7cb1b52016-12-09 09:52:16 -05002045 /* Don't adjust the buffer for hop count issue; icmp-error node
2046 * wants to see the IP headerr */
2047 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2048 {
2049 p0->current_data -= rw_len0;
2050 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002051
Dave Barachd7cb1b52016-12-09 09:52:16 -05002052 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2053 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2054 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002055
Neale Rannsb069a692017-03-15 12:34:25 -04002056 if (PREDICT_FALSE
2057 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2058 vnet_feature_arc_start (lm->output_feature_arc_index,
2059 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002060 }
2061 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2062 {
2063 p1->current_data -= rw_len1;
2064 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002065
Dave Barachd7cb1b52016-12-09 09:52:16 -05002066 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2067 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2068 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002069
Neale Rannsb069a692017-03-15 12:34:25 -04002070 if (PREDICT_FALSE
2071 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2072 vnet_feature_arc_start (lm->output_feature_arc_index,
2073 tx_sw_if_index1, &next1, p1);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002074 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002075
2076 /* Guess we are only writing on simple Ethernet header. */
2077 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002078 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002079
Neale Ranns5e575b12016-10-03 09:40:25 +01002080 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002081 {
2082 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2083 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2084 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002085 if (is_mcast)
2086 {
2087 /*
2088 * copy bytes from the IP address into the MAC rewrite
2089 */
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002090 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2091 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002092 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002093
Ed Warnickecb9cada2015-12-08 15:45:58 -07002094 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2095 to_next, n_left_to_next,
2096 pi0, pi1, next0, next1);
2097 }
2098
2099 while (n_left_from > 0 && n_left_to_next > 0)
2100 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002101 ip_adjacency_t *adj0;
2102 vlib_buffer_t *p0;
2103 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002104 u32 pi0, rw_len0;
2105 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002106 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002107
Ed Warnickecb9cada2015-12-08 15:45:58 -07002108 pi0 = to_next[0] = from[0];
2109
2110 p0 = vlib_get_buffer (vm, pi0);
2111
Neale Rannsf06aea52016-11-29 06:51:37 -08002112 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002113
Dave Barachd7cb1b52016-12-09 09:52:16 -05002114 /* We should never rewrite a pkt using the MISS adjacency */
2115 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002116
2117 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002118
Ed Warnickecb9cada2015-12-08 15:45:58 -07002119 ip0 = vlib_buffer_get_current (p0);
2120
2121 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002122 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002123
2124 /* Check hop limit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002125 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002126 {
2127 i32 hop_limit0 = ip0->hop_limit;
2128
2129 ASSERT (ip0->hop_limit > 0);
2130
2131 hop_limit0 -= 1;
2132
2133 ip0->hop_limit = hop_limit0;
2134
Dave Barachd7cb1b52016-12-09 09:52:16 -05002135 if (PREDICT_FALSE (hop_limit0 <= 0))
2136 {
2137 /*
2138 * If the hop count drops below 1 when forwarding, generate
2139 * an ICMP response.
2140 */
2141 error0 = IP6_ERROR_TIME_EXPIRED;
2142 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2143 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2144 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2145 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2146 0);
2147 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002148 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002149 else
2150 {
2151 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2152 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002153
Ed Warnickecb9cada2015-12-08 15:45:58 -07002154 /* Guess we are only writing on simple Ethernet header. */
2155 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002156
Ed Warnickecb9cada2015-12-08 15:45:58 -07002157 /* Update packet buffer attributes/set output interface. */
2158 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002159 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002160
Neale Ranns9c6a6132017-02-21 05:33:14 -08002161 if (do_counters)
2162 {
2163 vlib_increment_combined_counter
2164 (&adjacency_counters,
2165 cpu_index, adj_index0, 1,
2166 vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2167 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002168
2169 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002170 error0 =
2171 (vlib_buffer_length_in_chain (vm, p0) >
2172 adj0[0].
2173 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2174 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002175
Dave Barachd7cb1b52016-12-09 09:52:16 -05002176 /* Don't adjust the buffer for hop count issue; icmp-error node
2177 * wants to see the IP headerr */
2178 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2179 {
Chris Luke816f3e12016-06-14 16:24:47 -04002180 p0->current_data -= rw_len0;
2181 p0->current_length += rw_len0;
2182
Dave Barachd7cb1b52016-12-09 09:52:16 -05002183 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002184
Dave Barachd7cb1b52016-12-09 09:52:16 -05002185 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2186 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002187
Neale Rannsb069a692017-03-15 12:34:25 -04002188 if (PREDICT_FALSE
2189 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2190 vnet_feature_arc_start (lm->output_feature_arc_index,
2191 tx_sw_if_index0, &next0, p0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002192 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002193
Neale Ranns5e575b12016-10-03 09:40:25 +01002194 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002195 {
2196 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2197 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002198 if (is_mcast)
2199 {
Neale Ranns2e7fbcc2017-03-15 04:22:25 -07002200 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002201 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002202
Ed Warnickecb9cada2015-12-08 15:45:58 -07002203 p0->error = error_node->errors[error0];
2204
2205 from += 1;
2206 n_left_from -= 1;
2207 to_next += 1;
2208 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002209
Ed Warnickecb9cada2015-12-08 15:45:58 -07002210 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2211 to_next, n_left_to_next,
2212 pi0, next0);
2213 }
2214
2215 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2216 }
2217
2218 /* Need to do trace after rewrites to pick up new packet data. */
2219 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002220 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002221
2222 return frame->n_vectors;
2223}
2224
2225static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002226ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002227 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002228{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002229 if (adj_are_counters_enabled ())
2230 return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2231 else
2232 return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002233}
2234
2235static uword
2236ip6_rewrite_mcast (vlib_main_t * vm,
2237 vlib_node_runtime_t * node, vlib_frame_t * frame)
2238{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002239 if (adj_are_counters_enabled ())
2240 return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2241 else
2242 return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243}
2244
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002245static uword
2246ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002247 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002248{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002249 if (adj_are_counters_enabled ())
2250 return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2251 else
2252 return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002253}
2254
Dave Barachd7cb1b52016-12-09 09:52:16 -05002255/* *INDENT-OFF* */
2256VLIB_REGISTER_NODE (ip6_midchain_node) =
2257{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002258 .function = ip6_midchain,
2259 .name = "ip6-midchain",
2260 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002261 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002262 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002263 };
2264/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002265
Dave Barachd7cb1b52016-12-09 09:52:16 -05002266VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002267
Dave Barachd7cb1b52016-12-09 09:52:16 -05002268/* *INDENT-OFF* */
2269VLIB_REGISTER_NODE (ip6_rewrite_node) =
2270{
Neale Rannsf06aea52016-11-29 06:51:37 -08002271 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002272 .name = "ip6-rewrite",
2273 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002274 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002275 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002276 .next_nodes =
2277 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002278 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002279 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002280 },
2281};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002282/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002283
Neale Rannsf06aea52016-11-29 06:51:37 -08002284VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002285
Neale Ranns32e1c012016-11-22 17:07:28 +00002286/* *INDENT-OFF* */
2287VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2288{
2289 .function = ip6_rewrite_mcast,
2290 .name = "ip6-rewrite-mcast",
2291 .vector_size = sizeof (u32),
2292 .format_trace = format_ip6_rewrite_trace,
2293 .sibling_of = "ip6-rewrite",
2294};
2295/* *INDENT-ON* */
2296
2297VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2298
Ole Troan944f5482016-05-24 11:56:58 +02002299/*
2300 * Hop-by-Hop handling
2301 */
Ole Troan944f5482016-05-24 11:56:58 +02002302ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2303
2304#define foreach_ip6_hop_by_hop_error \
2305_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2306_(FORMAT, "incorrectly formatted hop-by-hop options") \
2307_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2308
Neale Ranns32e1c012016-11-22 17:07:28 +00002309/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002310typedef enum
2311{
Ole Troan944f5482016-05-24 11:56:58 +02002312#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2313 foreach_ip6_hop_by_hop_error
2314#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002315 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002316} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002317/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002318
2319/*
2320 * Primary h-b-h handler trace support
2321 * We work pretty hard on the problem for obvious reasons
2322 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002323typedef struct
2324{
Ole Troan944f5482016-05-24 11:56:58 +02002325 u32 next_index;
2326 u32 trace_len;
2327 u8 option_data[256];
2328} ip6_hop_by_hop_trace_t;
2329
2330vlib_node_registration_t ip6_hop_by_hop_node;
2331
Dave Barachd7cb1b52016-12-09 09:52:16 -05002332static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002333#define _(sym,string) string,
2334 foreach_ip6_hop_by_hop_error
2335#undef _
2336};
2337
Shwetha Bhandari78372a92017-01-18 12:43:54 +05302338u8 *
2339format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2340{
2341 ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2342 int total_len = va_arg (*args, int);
2343 ip6_hop_by_hop_option_t *opt0, *limit0;
2344 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2345 u8 type0;
2346
2347 s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2348 hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2349
2350 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2351 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2352
2353 while (opt0 < limit0)
2354 {
2355 type0 = opt0->type;
2356 switch (type0)
2357 {
2358 case 0: /* Pad, just stop */
2359 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2360 break;
2361
2362 default:
2363 if (hm->trace[type0])
2364 {
2365 s = (*hm->trace[type0]) (s, opt0);
2366 }
2367 else
2368 {
2369 s =
2370 format (s, "\n unrecognized option %d length %d", type0,
2371 opt0->length);
2372 }
2373 opt0 =
2374 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2375 sizeof (ip6_hop_by_hop_option_t));
2376 break;
2377 }
2378 }
2379 return s;
2380}
2381
Ole Troan944f5482016-05-24 11:56:58 +02002382static u8 *
2383format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2384{
2385 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2386 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002387 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002388 ip6_hop_by_hop_header_t *hbh0;
2389 ip6_hop_by_hop_option_t *opt0, *limit0;
2390 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2391
2392 u8 type0;
2393
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002395
2396 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002397 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002398
Dave Barachd7cb1b52016-12-09 09:52:16 -05002399 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2400 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002401
Dave Barachd7cb1b52016-12-09 09:52:16 -05002402 while (opt0 < limit0)
2403 {
2404 type0 = opt0->type;
2405 switch (type0)
2406 {
2407 case 0: /* Pad, just stop */
2408 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2409 break;
Ole Troan944f5482016-05-24 11:56:58 +02002410
Dave Barachd7cb1b52016-12-09 09:52:16 -05002411 default:
2412 if (hm->trace[type0])
2413 {
2414 s = (*hm->trace[type0]) (s, opt0);
2415 }
2416 else
2417 {
2418 s =
2419 format (s, "\n unrecognized option %d length %d", type0,
2420 opt0->length);
2421 }
2422 opt0 =
2423 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2424 sizeof (ip6_hop_by_hop_option_t));
2425 break;
2426 }
Ole Troan944f5482016-05-24 11:56:58 +02002427 }
Ole Troan944f5482016-05-24 11:56:58 +02002428 return s;
2429}
2430
Dave Barachd7cb1b52016-12-09 09:52:16 -05002431always_inline u8
2432ip6_scan_hbh_options (vlib_buffer_t * b0,
2433 ip6_header_t * ip0,
2434 ip6_hop_by_hop_header_t * hbh0,
2435 ip6_hop_by_hop_option_t * opt0,
2436 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002437{
2438 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2439 u8 type0;
2440 u8 error0 = 0;
2441
2442 while (opt0 < limit0)
2443 {
2444 type0 = opt0->type;
2445 switch (type0)
2446 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002447 case 0: /* Pad1 */
2448 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002449 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002450 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002451 break;
2452 default:
2453 if (hm->options[type0])
2454 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002455 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2456 {
Shwethaa91cbe62016-08-08 15:51:04 +01002457 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002458 return (error0);
2459 }
Shwethaa91cbe62016-08-08 15:51:04 +01002460 }
2461 else
2462 {
2463 /* Unrecognized mandatory option, check the two high order bits */
2464 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2465 {
2466 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2467 break;
2468 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2469 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2470 *next0 = IP_LOOKUP_NEXT_DROP;
2471 break;
2472 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2473 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2474 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002475 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2476 ICMP6_parameter_problem_unrecognized_option,
2477 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002478 break;
2479 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2480 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002481 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002482 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002483 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2484 icmp6_error_set_vnet_buffer (b0,
2485 ICMP6_parameter_problem,
2486 ICMP6_parameter_problem_unrecognized_option,
2487 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002488 }
2489 else
2490 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002491 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002492 }
2493 break;
2494 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002495 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002496 }
2497 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002498 opt0 =
2499 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2500 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002501 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002502 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002503}
2504
Ole Troan944f5482016-05-24 11:56:58 +02002505/*
2506 * Process the Hop-by-Hop Options header
2507 */
2508static uword
2509ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002510 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002511{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002512 vlib_node_runtime_t *error_node =
2513 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002514 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2515 u32 n_left_from, *from, *to_next;
2516 ip_lookup_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002517 ip6_main_t *im = &ip6_main;
Ole Troan944f5482016-05-24 11:56:58 +02002518 ip_lookup_main_t *lm = &im->lookup_main;
2519
2520 from = vlib_frame_vector_args (frame);
2521 n_left_from = frame->n_vectors;
2522 next_index = node->cached_next_index;
2523
Dave Barachd7cb1b52016-12-09 09:52:16 -05002524 while (n_left_from > 0)
2525 {
2526 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002527
Dave Barachd7cb1b52016-12-09 09:52:16 -05002528 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002529
Dave Barachd7cb1b52016-12-09 09:52:16 -05002530 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002531 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002532 u32 bi0, bi1;
2533 vlib_buffer_t *b0, *b1;
2534 u32 next0, next1;
2535 ip6_header_t *ip0, *ip1;
2536 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2537 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2538 u8 error0 = 0, error1 = 0;
2539
2540 /* Prefetch next iteration. */
2541 {
2542 vlib_buffer_t *p2, *p3;
2543
2544 p2 = vlib_get_buffer (vm, from[2]);
2545 p3 = vlib_get_buffer (vm, from[3]);
2546
2547 vlib_prefetch_buffer_header (p2, LOAD);
2548 vlib_prefetch_buffer_header (p3, LOAD);
2549
2550 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2551 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002552 }
2553
Dave Barachd7cb1b52016-12-09 09:52:16 -05002554 /* Speculatively enqueue b0, b1 to the current next frame */
2555 to_next[0] = bi0 = from[0];
2556 to_next[1] = bi1 = from[1];
2557 from += 2;
2558 to_next += 2;
2559 n_left_from -= 2;
2560 n_left_to_next -= 2;
2561
2562 b0 = vlib_get_buffer (vm, bi0);
2563 b1 = vlib_get_buffer (vm, bi1);
2564
2565 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2566 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2567 ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2568 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2569 ip_adjacency_t *adj1 = ip_get_adjacency (lm, adj_index1);
2570
2571 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2572 next0 = adj0->lookup_next_index;
2573 next1 = adj1->lookup_next_index;
2574
2575 ip0 = vlib_buffer_get_current (b0);
2576 ip1 = vlib_buffer_get_current (b1);
2577 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2578 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2579 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2580 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2581 limit0 =
2582 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2583 ((hbh0->length + 1) << 3));
2584 limit1 =
2585 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2586 ((hbh1->length + 1) << 3));
2587
2588 /*
2589 * Basic validity checks
2590 */
2591 if ((hbh0->length + 1) << 3 >
2592 clib_net_to_host_u16 (ip0->payload_length))
2593 {
2594 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2595 next0 = IP_LOOKUP_NEXT_DROP;
2596 goto outdual;
2597 }
2598 /* Scan the set of h-b-h options, process ones that we understand */
2599 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2600
2601 if ((hbh1->length + 1) << 3 >
2602 clib_net_to_host_u16 (ip1->payload_length))
2603 {
2604 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2605 next1 = IP_LOOKUP_NEXT_DROP;
2606 goto outdual;
2607 }
2608 /* Scan the set of h-b-h options, process ones that we understand */
2609 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2610
2611 outdual:
2612 /* Has the classifier flagged this buffer for special treatment? */
2613 if (PREDICT_FALSE
2614 ((error0 == 0)
2615 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2616 next0 = hm->next_override;
2617
2618 /* Has the classifier flagged this buffer for special treatment? */
2619 if (PREDICT_FALSE
2620 ((error1 == 0)
2621 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2622 next1 = hm->next_override;
2623
2624 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2625 {
2626 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2627 {
2628 ip6_hop_by_hop_trace_t *t =
2629 vlib_add_trace (vm, node, b0, sizeof (*t));
2630 u32 trace_len = (hbh0->length + 1) << 3;
2631 t->next_index = next0;
2632 /* Capture the h-b-h option verbatim */
2633 trace_len =
2634 trace_len <
2635 ARRAY_LEN (t->option_data) ? trace_len :
2636 ARRAY_LEN (t->option_data);
2637 t->trace_len = trace_len;
2638 clib_memcpy (t->option_data, hbh0, trace_len);
2639 }
2640 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2641 {
2642 ip6_hop_by_hop_trace_t *t =
2643 vlib_add_trace (vm, node, b1, sizeof (*t));
2644 u32 trace_len = (hbh1->length + 1) << 3;
2645 t->next_index = next1;
2646 /* Capture the h-b-h option verbatim */
2647 trace_len =
2648 trace_len <
2649 ARRAY_LEN (t->option_data) ? trace_len :
2650 ARRAY_LEN (t->option_data);
2651 t->trace_len = trace_len;
2652 clib_memcpy (t->option_data, hbh1, trace_len);
2653 }
2654
2655 }
2656
2657 b0->error = error_node->errors[error0];
2658 b1->error = error_node->errors[error1];
2659
2660 /* verify speculative enqueue, maybe switch current next frame */
2661 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2662 n_left_to_next, bi0, bi1, next0,
2663 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002664 }
2665
Dave Barachd7cb1b52016-12-09 09:52:16 -05002666 while (n_left_from > 0 && n_left_to_next > 0)
2667 {
2668 u32 bi0;
2669 vlib_buffer_t *b0;
2670 u32 next0;
2671 ip6_header_t *ip0;
2672 ip6_hop_by_hop_header_t *hbh0;
2673 ip6_hop_by_hop_option_t *opt0, *limit0;
2674 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002675
Dave Barachd7cb1b52016-12-09 09:52:16 -05002676 /* Speculatively enqueue b0 to the current next frame */
2677 bi0 = from[0];
2678 to_next[0] = bi0;
2679 from += 1;
2680 to_next += 1;
2681 n_left_from -= 1;
2682 n_left_to_next -= 1;
2683
2684 b0 = vlib_get_buffer (vm, bi0);
2685 /*
2686 * Default use the next_index from the adjacency.
2687 * A HBH option rarely redirects to a different node
2688 */
2689 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2690 ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2691 next0 = adj0->lookup_next_index;
2692
2693 ip0 = vlib_buffer_get_current (b0);
2694 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2695 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2696 limit0 =
2697 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2698 ((hbh0->length + 1) << 3));
2699
2700 /*
2701 * Basic validity checks
2702 */
2703 if ((hbh0->length + 1) << 3 >
2704 clib_net_to_host_u16 (ip0->payload_length))
2705 {
2706 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2707 next0 = IP_LOOKUP_NEXT_DROP;
2708 goto out0;
2709 }
2710
2711 /* Scan the set of h-b-h options, process ones that we understand */
2712 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2713
2714 out0:
2715 /* Has the classifier flagged this buffer for special treatment? */
2716 if (PREDICT_FALSE
2717 ((error0 == 0)
2718 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2719 next0 = hm->next_override;
2720
2721 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2722 {
2723 ip6_hop_by_hop_trace_t *t =
2724 vlib_add_trace (vm, node, b0, sizeof (*t));
2725 u32 trace_len = (hbh0->length + 1) << 3;
2726 t->next_index = next0;
2727 /* Capture the h-b-h option verbatim */
2728 trace_len =
2729 trace_len <
2730 ARRAY_LEN (t->option_data) ? trace_len :
2731 ARRAY_LEN (t->option_data);
2732 t->trace_len = trace_len;
2733 clib_memcpy (t->option_data, hbh0, trace_len);
2734 }
2735
2736 b0->error = error_node->errors[error0];
2737
2738 /* verify speculative enqueue, maybe switch current next frame */
2739 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2740 n_left_to_next, bi0, next0);
2741 }
2742 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002743 }
Ole Troan944f5482016-05-24 11:56:58 +02002744 return frame->n_vectors;
2745}
2746
Dave Barachd7cb1b52016-12-09 09:52:16 -05002747/* *INDENT-OFF* */
2748VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2749{
Ole Troan944f5482016-05-24 11:56:58 +02002750 .function = ip6_hop_by_hop,
2751 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002752 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002753 .vector_size = sizeof (u32),
2754 .format_trace = format_ip6_hop_by_hop_trace,
2755 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002756 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002757 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002758 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002759};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002760/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002761
Dave Barach5331c722016-08-17 11:54:30 -04002762VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002763
2764static clib_error_t *
2765ip6_hop_by_hop_init (vlib_main_t * vm)
2766{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002767 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2768 memset (hm->options, 0, sizeof (hm->options));
2769 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002770 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002771 return (0);
2772}
2773
2774VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2775
Dave Barachd7cb1b52016-12-09 09:52:16 -05002776void
2777ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002778{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002779 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002780
2781 hm->next_override = next;
2782}
2783
Ole Troan944f5482016-05-24 11:56:58 +02002784int
2785ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002786 int options (vlib_buffer_t * b, ip6_header_t * ip,
2787 ip6_hop_by_hop_option_t * opt),
2788 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002789{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002790 ip6_main_t *im = &ip6_main;
2791 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002792
2793 ASSERT (option < ARRAY_LEN (hm->options));
2794
2795 /* Already registered */
2796 if (hm->options[option])
2797 return (-1);
2798
2799 hm->options[option] = options;
2800 hm->trace[option] = trace;
2801
2802 /* Set global variable */
2803 im->hbh_enabled = 1;
2804
2805 return (0);
2806}
2807
2808int
2809ip6_hbh_unregister_option (u8 option)
2810{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002811 ip6_main_t *im = &ip6_main;
2812 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002813
2814 ASSERT (option < ARRAY_LEN (hm->options));
2815
2816 /* Not registered */
2817 if (!hm->options[option])
2818 return (-1);
2819
2820 hm->options[option] = NULL;
2821 hm->trace[option] = NULL;
2822
2823 /* Disable global knob if this was the last option configured */
2824 int i;
2825 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002826 for (i = 0; i < 256; i++)
2827 {
2828 if (hm->options[option])
2829 {
2830 found = true;
2831 break;
2832 }
Ole Troan944f5482016-05-24 11:56:58 +02002833 }
Ole Troan944f5482016-05-24 11:56:58 +02002834 if (!found)
2835 im->hbh_enabled = 0;
2836
2837 return (0);
2838}
2839
Ed Warnickecb9cada2015-12-08 15:45:58 -07002840/* Global IP6 main. */
2841ip6_main_t ip6_main;
2842
2843static clib_error_t *
2844ip6_lookup_init (vlib_main_t * vm)
2845{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002846 ip6_main_t *im = &ip6_main;
2847 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002848 uword i;
2849
Damjan Marion8b3191e2016-11-09 19:54:20 +01002850 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2851 return error;
2852
Ed Warnickecb9cada2015-12-08 15:45:58 -07002853 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2854 {
2855 u32 j, i0, i1;
2856
2857 i0 = i / 32;
2858 i1 = i % 32;
2859
2860 for (j = 0; j < i0; j++)
2861 im->fib_masks[i].as_u32[j] = ~0;
2862
2863 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 im->fib_masks[i].as_u32[i0] =
2865 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866 }
2867
2868 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2869
2870 if (im->lookup_table_nbuckets == 0)
2871 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2872
Dave Barachd7cb1b52016-12-09 09:52:16 -05002873 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874
2875 if (im->lookup_table_size == 0)
2876 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002877
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2879 "ip6 FIB fwding table",
2880 im->lookup_table_nbuckets, im->lookup_table_size);
2881 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2882 "ip6 FIB non-fwding table",
2883 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002884
Ed Warnickecb9cada2015-12-08 15:45:58 -07002885 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002886 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002887 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888
2889 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002890 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891 pn = pg_get_node (ip6_lookup_node.index);
2892 pn->unformat_edit = unformat_pg_ip6_header;
2893 }
2894
Ole Troan944f5482016-05-24 11:56:58 +02002895 /* Unless explicitly configured, don't process HBH options */
2896 im->hbh_enabled = 0;
2897
Ed Warnickecb9cada2015-12-08 15:45:58 -07002898 {
2899 icmp6_neighbor_solicitation_header_t p;
2900
2901 memset (&p, 0, sizeof (p));
2902
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903 p.ip.ip_version_traffic_class_and_flow_label =
2904 clib_host_to_net_u32 (0x6 << 28);
2905 p.ip.payload_length =
2906 clib_host_to_net_u16 (sizeof (p) -
2907 STRUCT_OFFSET_OF
2908 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002909 p.ip.protocol = IP_PROTOCOL_ICMP6;
2910 p.ip.hop_limit = 255;
2911 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2912
2913 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2914
Dave Barachd7cb1b52016-12-09 09:52:16 -05002915 p.link_layer_option.header.type =
2916 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2917 p.link_layer_option.header.n_data_u64s =
2918 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919
2920 vlib_packet_template_init (vm,
2921 &im->discover_neighbor_packet_template,
2922 &p, sizeof (p),
2923 /* alloc chunk size */ 8,
2924 "ip6 neighbor discovery");
2925 }
2926
Dave Barach203c6322016-06-26 10:29:03 -04002927 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002928}
2929
2930VLIB_INIT_FUNCTION (ip6_lookup_init);
2931
2932static clib_error_t *
2933add_del_ip6_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002934 unformat_input_t * input,
2935 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002936{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002937 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns4008ac92017-02-13 23:20:04 -08002938 ip_interface_address_t *ia;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002939 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002940 u32 sw_if_index, table_id;
2941
2942 sw_if_index = ~0;
2943
Dave Barachd7cb1b52016-12-09 09:52:16 -05002944 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002945 {
2946 error = clib_error_return (0, "unknown interface `%U'",
2947 format_unformat_error, input);
2948 goto done;
2949 }
2950
2951 if (unformat (input, "%d", &table_id))
2952 ;
2953 else
2954 {
2955 error = clib_error_return (0, "expected table id `%U'",
2956 format_unformat_error, input);
2957 goto done;
2958 }
2959
Neale Ranns4008ac92017-02-13 23:20:04 -08002960 /*
2961 * If the interface already has in IP address, then a change int
2962 * VRF is not allowed. The IP address applied must first be removed.
2963 * We do not do that automatically here, since VPP has no knowledge
2964 * of whether thoses subnets are valid in the destination VRF.
2965 */
2966 /* *INDENT-OFF* */
2967 foreach_ip_interface_address (&ip6_main.lookup_main,
2968 ia, sw_if_index,
2969 1 /* honor unnumbered */,
2970 ({
2971 ip4_address_t * a;
2972
2973 a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
2974 error = clib_error_return (0, "interface %U has address %U",
2975 format_vnet_sw_if_index_name, vnm,
2976 sw_if_index,
2977 format_ip6_address, a);
2978 goto done;
2979 }));
2980 /* *INDENT-ON* */
2981
Ed Warnickecb9cada2015-12-08 15:45:58 -07002982 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002983 u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2984 table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002985
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002986 vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
2987 ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002988
2989 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2990 table_id);
2991
2992 vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
2993 ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002994 }
2995
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002996
Dave Barachd7cb1b52016-12-09 09:52:16 -05002997done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002998 return error;
2999}
3000
Billy McFall0683c9c2016-10-13 08:27:31 -04003001/*?
3002 * Place the indicated interface into the supplied IPv6 FIB table (also known
3003 * as a VRF). If the FIB table does not exist, this command creates it. To
3004 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3005 * FIB table will only be displayed if a route has been added to the table, or
3006 * an IP Address is assigned to an interface in the table (which adds a route
3007 * automatically).
3008 *
Neale Ranns4008ac92017-02-13 23:20:04 -08003009 * @note IP addresses added after setting the interface IP table are added to
3010 * the indicated FIB table. If an IP address is added prior to changing the
3011 * table then this is an error. The control plane must remove these addresses
3012 * first and then change the table. VPP will not automatically move the
3013 * addresses from the old to the new table as it does not know the validity
3014 * of such a change.
Billy McFall0683c9c2016-10-13 08:27:31 -04003015 *
3016 * @cliexpar
3017 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3018 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3019 ?*/
3020/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003021VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3022{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003023 .path = "set interface ip6 table",
3024 .function = add_del_ip6_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04003025 .short_help = "set interface ip6 table <interface> <table-id>"
Ed Warnickecb9cada2015-12-08 15:45:58 -07003026};
Billy McFall0683c9c2016-10-13 08:27:31 -04003027/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003028
Dave Barach75fc8542016-10-11 16:16:02 -04003029void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003030ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3031 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003032{
3033 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3034 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003035 ip->as_u8[8] = mac[0] ^ (1 << 1);
3036 ip->as_u8[9] = mac[1];
3037 ip->as_u8[10] = mac[2];
3038 ip->as_u8[11] = 0xFF;
3039 ip->as_u8[12] = 0xFE;
3040 ip->as_u8[13] = mac[3];
3041 ip->as_u8[14] = mac[4];
3042 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003043}
3044
Dave Barach75fc8542016-10-11 16:16:02 -04003045void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3047 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003048{
3049 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003050 mac[0] = ip->as_u8[8] ^ (1 << 1);
3051 mac[1] = ip->as_u8[9];
3052 mac[2] = ip->as_u8[10];
3053 mac[3] = ip->as_u8[13];
3054 mac[4] = ip->as_u8[14];
3055 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003056}
3057
Dave Barach75fc8542016-10-11 16:16:02 -04003058static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003059test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003060 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003061{
3062 u8 mac[6];
3063 ip6_address_t _a, *a = &_a;
3064
3065 if (unformat (input, "%U", unformat_ethernet_address, mac))
3066 {
3067 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003068 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003069 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3070 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003071 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003072 }
Dave Barach75fc8542016-10-11 16:16:02 -04003073
Ed Warnickecb9cada2015-12-08 15:45:58 -07003074 return 0;
3075}
3076
Billy McFall0683c9c2016-10-13 08:27:31 -04003077/*?
3078 * This command converts the given MAC Address into an IPv6 link-local
3079 * address.
3080 *
3081 * @cliexpar
3082 * Example of how to create an IPv6 link-local address:
3083 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3084 * Link local address: fe80::14d9:e0ff:fe91:7986
3085 * Original MAC address: 16:d9:e0:91:79:86
3086 * @cliexend
3087?*/
3088/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003089VLIB_CLI_COMMAND (test_link_command, static) =
3090{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003091 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003092 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003093 .short_help = "test ip6 link <mac-address>",
3094};
Billy McFall0683c9c2016-10-13 08:27:31 -04003095/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003096
Dave Barachd7cb1b52016-12-09 09:52:16 -05003097int
3098vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003099{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003100 ip6_main_t *im6 = &ip6_main;
3101 ip6_fib_t *fib;
3102 uword *p = hash_get (im6->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003103
3104 if (p == 0)
3105 return -1;
3106
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003107 fib = ip6_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003108
3109 fib->flow_hash_config = flow_hash_config;
3110 return 1;
3111}
3112
3113static clib_error_t *
3114set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003115 unformat_input_t * input,
3116 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003117{
3118 int matched = 0;
3119 u32 table_id = 0;
3120 u32 flow_hash_config = 0;
3121 int rv;
3122
Dave Barachd7cb1b52016-12-09 09:52:16 -05003123 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3124 {
3125 if (unformat (input, "table %d", &table_id))
3126 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003127#define _(a,v) \
3128 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003129 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003130#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003131 else
3132 break;
3133 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003134
3135 if (matched == 0)
3136 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003137 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003138
Ed Warnickecb9cada2015-12-08 15:45:58 -07003139 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3140 switch (rv)
3141 {
3142 case 1:
3143 break;
3144
3145 case -1:
3146 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003147
Ed Warnickecb9cada2015-12-08 15:45:58 -07003148 default:
3149 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3150 break;
3151 }
Dave Barach75fc8542016-10-11 16:16:02 -04003152
Ed Warnickecb9cada2015-12-08 15:45:58 -07003153 return 0;
3154}
3155
Billy McFall0683c9c2016-10-13 08:27:31 -04003156/*?
3157 * Configure the set of IPv6 fields used by the flow hash.
3158 *
3159 * @cliexpar
3160 * @parblock
3161 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003162 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3163 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003164 * Example of display the configured flow hash:
3165 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003166 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3167 * @::/0
3168 * unicast-ip6-chain
3169 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3170 * [0] [@0]: dpo-drop ip6
3171 * fe80::/10
3172 * unicast-ip6-chain
3173 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3174 * [0] [@2]: dpo-receive
3175 * ff02::1/128
3176 * unicast-ip6-chain
3177 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3178 * [0] [@2]: dpo-receive
3179 * ff02::2/128
3180 * unicast-ip6-chain
3181 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3182 * [0] [@2]: dpo-receive
3183 * ff02::16/128
3184 * unicast-ip6-chain
3185 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3186 * [0] [@2]: dpo-receive
3187 * ff02::1:ff00:0/104
3188 * unicast-ip6-chain
3189 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3190 * [0] [@2]: dpo-receive
3191 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3192 * @::/0
3193 * unicast-ip6-chain
3194 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3195 * [0] [@0]: dpo-drop ip6
3196 * @::a:1:1:0:4/126
3197 * unicast-ip6-chain
3198 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3199 * [0] [@4]: ipv6-glean: af_packet0
3200 * @::a:1:1:0:7/128
3201 * unicast-ip6-chain
3202 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3203 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3204 * fe80::/10
3205 * unicast-ip6-chain
3206 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3207 * [0] [@2]: dpo-receive
3208 * fe80::fe:3eff:fe3e:9222/128
3209 * unicast-ip6-chain
3210 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3211 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3212 * ff02::1/128
3213 * unicast-ip6-chain
3214 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3215 * [0] [@2]: dpo-receive
3216 * ff02::2/128
3217 * unicast-ip6-chain
3218 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3219 * [0] [@2]: dpo-receive
3220 * ff02::16/128
3221 * unicast-ip6-chain
3222 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3223 * [0] [@2]: dpo-receive
3224 * ff02::1:ff00:0/104
3225 * unicast-ip6-chain
3226 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3227 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003228 * @cliexend
3229 * @endparblock
3230?*/
3231/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003232VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3233{
3234 .path = "set ip6 flow-hash",
3235 .short_help =
3236 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3237 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003238};
Billy McFall0683c9c2016-10-13 08:27:31 -04003239/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003240
3241static clib_error_t *
3242show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003243 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003244{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003245 ip6_main_t *im = &ip6_main;
3246 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003248
Ed Warnickecb9cada2015-12-08 15:45:58 -07003249 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003250 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003251 {
3252 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003253 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003254 }
3255 return 0;
3256}
3257
3258
3259
Billy McFall0683c9c2016-10-13 08:27:31 -04003260/*?
3261 * Display the set of protocols handled by the local IPv6 stack.
3262 *
3263 * @cliexpar
3264 * Example of how to display local protocol table:
3265 * @cliexstart{show ip6 local}
3266 * Protocols handled by ip6_local
3267 * 17
3268 * 43
3269 * 58
3270 * 115
3271 * @cliexend
3272?*/
3273/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003274VLIB_CLI_COMMAND (show_ip6_local, static) =
3275{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003276 .path = "show ip6 local",
3277 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003278 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003279};
Billy McFall0683c9c2016-10-13 08:27:31 -04003280/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003281
Dave Barachd7cb1b52016-12-09 09:52:16 -05003282int
3283vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3284 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003285{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003286 vnet_main_t *vnm = vnet_get_main ();
3287 vnet_interface_main_t *im = &vnm->interface_main;
3288 ip6_main_t *ipm = &ip6_main;
3289 ip_lookup_main_t *lm = &ipm->lookup_main;
3290 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003291 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003292
3293 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3294 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3295
3296 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3297 return VNET_API_ERROR_NO_SUCH_ENTRY;
3298
3299 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003300 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003301
Neale Ranns6cfc39c2017-02-14 01:44:25 -08003302 if_addr = ip6_interface_first_address (ipm, sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003303
3304 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003305 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003306 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003307 .fp_len = 128,
3308 .fp_proto = FIB_PROTOCOL_IP6,
3309 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003310 };
3311 u32 fib_index;
3312
Dave Barachd7cb1b52016-12-09 09:52:16 -05003313 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3314 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003315
3316
Dave Barachd7cb1b52016-12-09 09:52:16 -05003317 if (table_index != (u32) ~ 0)
3318 {
3319 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003320
Dave Barachd7cb1b52016-12-09 09:52:16 -05003321 dpo_set (&dpo,
3322 DPO_CLASSIFY,
3323 DPO_PROTO_IP6,
3324 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003325
Dave Barachd7cb1b52016-12-09 09:52:16 -05003326 fib_table_entry_special_dpo_add (fib_index,
3327 &pfx,
3328 FIB_SOURCE_CLASSIFY,
3329 FIB_ENTRY_FLAG_NONE, &dpo);
3330 dpo_reset (&dpo);
3331 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003332 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003333 {
3334 fib_table_entry_special_remove (fib_index,
3335 &pfx, FIB_SOURCE_CLASSIFY);
3336 }
3337 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003338
Ed Warnickecb9cada2015-12-08 15:45:58 -07003339 return 0;
3340}
3341
3342static clib_error_t *
3343set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003344 unformat_input_t * input,
3345 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003346{
3347 u32 table_index = ~0;
3348 int table_index_set = 0;
3349 u32 sw_if_index = ~0;
3350 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003351
Dave Barachd7cb1b52016-12-09 09:52:16 -05003352 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3353 {
3354 if (unformat (input, "table-index %d", &table_index))
3355 table_index_set = 1;
3356 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3357 vnet_get_main (), &sw_if_index))
3358 ;
3359 else
3360 break;
3361 }
Dave Barach75fc8542016-10-11 16:16:02 -04003362
Ed Warnickecb9cada2015-12-08 15:45:58 -07003363 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003364 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003365
Ed Warnickecb9cada2015-12-08 15:45:58 -07003366 if (sw_if_index == ~0)
3367 return clib_error_return (0, "interface / subif must be specified");
3368
3369 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3370
3371 switch (rv)
3372 {
3373 case 0:
3374 break;
3375
3376 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3377 return clib_error_return (0, "No such interface");
3378
3379 case VNET_API_ERROR_NO_SUCH_ENTRY:
3380 return clib_error_return (0, "No such classifier table");
3381 }
3382 return 0;
3383}
3384
Billy McFall0683c9c2016-10-13 08:27:31 -04003385/*?
3386 * Assign a classification table to an interface. The classification
3387 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3388 * commands. Once the table is create, use this command to filter packets
3389 * on an interface.
3390 *
3391 * @cliexpar
3392 * Example of how to assign a classification table to an interface:
3393 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3394?*/
3395/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003396VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3397{
3398 .path = "set ip6 classify",
3399 .short_help =
3400 "set ip6 classify intfc <interface> table-index <classify-idx>",
3401 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003402};
Billy McFall0683c9c2016-10-13 08:27:31 -04003403/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003404
3405static clib_error_t *
3406ip6_config (vlib_main_t * vm, unformat_input_t * input)
3407{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003408 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003409 uword heapsize = 0;
3410 u32 tmp;
3411 u32 nbuckets = 0;
3412
Dave Barachd7cb1b52016-12-09 09:52:16 -05003413 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3414 {
3415 if (unformat (input, "hash-buckets %d", &tmp))
3416 nbuckets = tmp;
3417 else if (unformat (input, "heap-size %dm", &tmp))
3418 heapsize = ((u64) tmp) << 20;
3419 else if (unformat (input, "heap-size %dM", &tmp))
3420 heapsize = ((u64) tmp) << 20;
3421 else if (unformat (input, "heap-size %dg", &tmp))
3422 heapsize = ((u64) tmp) << 30;
3423 else if (unformat (input, "heap-size %dG", &tmp))
3424 heapsize = ((u64) tmp) << 30;
3425 else
3426 return clib_error_return (0, "unknown input '%U'",
3427 format_unformat_error, input);
3428 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003429
3430 im->lookup_table_nbuckets = nbuckets;
3431 im->lookup_table_size = heapsize;
3432
3433 return 0;
3434}
3435
3436VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003437
3438/*
3439 * fd.io coding-style-patch-verification: ON
3440 *
3441 * Local Variables:
3442 * eval: (c-set-style "gnu")
3443 * End:
3444 */