blob: 06c20bbaa1288b8b9c00e8a79ad623eb02fc035e [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>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010045#include <vnet/fib/ip6_fib.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000046#include <vnet/mfib/ip6_mfib.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010047#include <vnet/dpo/load_balance.h>
48#include <vnet/dpo/classify_dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
50#include <vppinfra/bihash_template.c>
51
Billy McFall0683c9c2016-10-13 08:27:31 -040052/**
53 * @file
54 * @brief IPv6 Forwarding.
55 *
56 * This file contains the source code for IPv6 forwarding.
57 */
58
Pierre Pfister0febaf12016-06-08 12:23:21 +010059void
60ip6_forward_next_trace (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050061 vlib_node_runtime_t * node,
62 vlib_frame_t * frame,
63 vlib_rx_or_tx_t which_adj_index);
Pierre Pfister0febaf12016-06-08 12:23:21 +010064
Damjan Marionaca64c92016-04-13 09:48:56 +020065always_inline uword
66ip6_lookup_inline (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -050067 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barachd7cb1b52016-12-09 09:52:16 -050069 ip6_main_t *im = &ip6_main;
70 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
71 u32 n_left_from, n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -050073 u32 cpu_index = os_get_cpu_number ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070074
75 from = vlib_frame_vector_args (frame);
76 n_left_from = frame->n_vectors;
77 next = node->cached_next_index;
78
79 while (n_left_from > 0)
80 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050081 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
83 while (n_left_from >= 4 && n_left_to_next >= 2)
84 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050085 vlib_buffer_t *p0, *p1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010086 u32 pi0, pi1, lbi0, lbi1, wrong_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 ip_lookup_next_t next0, next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -050088 ip6_header_t *ip0, *ip1;
89 ip6_address_t *dst_addr0, *dst_addr1;
90 u32 fib_index0, fib_index1;
91 u32 flow_hash_config0, flow_hash_config1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +010092 const dpo_id_t *dpo0, *dpo1;
93 const load_balance_t *lb0, *lb1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
95 /* Prefetch next iteration. */
96 {
Dave Barachd7cb1b52016-12-09 09:52:16 -050097 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 p2 = vlib_get_buffer (vm, from[2]);
100 p3 = vlib_get_buffer (vm, from[3]);
101
102 vlib_prefetch_buffer_header (p2, LOAD);
103 vlib_prefetch_buffer_header (p3, LOAD);
104 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
105 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
106 }
107
108 pi0 = to_next[0] = from[0];
109 pi1 = to_next[1] = from[1];
110
111 p0 = vlib_get_buffer (vm, pi0);
112 p1 = vlib_get_buffer (vm, pi1);
113
114 ip0 = vlib_buffer_get_current (p0);
115 ip1 = vlib_buffer_get_current (p1);
116
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100117 dst_addr0 = &ip0->dst_address;
118 dst_addr1 = &ip1->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200119
Dave Barachd7cb1b52016-12-09 09:52:16 -0500120 fib_index0 =
121 vec_elt (im->fib_index_by_sw_if_index,
122 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
123 fib_index1 =
124 vec_elt (im->fib_index_by_sw_if_index,
125 vnet_buffer (p1)->sw_if_index[VLIB_RX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126
Dave Barachd7cb1b52016-12-09 09:52:16 -0500127 fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
128 fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
129 fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
130 fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100132 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
133 lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100135 lb0 = load_balance_get (lbi0);
136 lb1 = load_balance_get (lbi1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137
Dave Barachd7cb1b52016-12-09 09:52:16 -0500138 vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
Dave Barachd7cb1b52016-12-09 09:52:16 -0500140 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
141 {
142 flow_hash_config0 = lb0->lb_hash_config;
143 vnet_buffer (p0)->ip.flow_hash =
144 ip6_compute_flow_hash (ip0, flow_hash_config0);
145 }
146 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
147 {
148 flow_hash_config1 = lb1->lb_hash_config;
149 vnet_buffer (p1)->ip.flow_hash =
150 ip6_compute_flow_hash (ip1, flow_hash_config1);
151 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100153 ASSERT (lb0->lb_n_buckets > 0);
154 ASSERT (lb1->lb_n_buckets > 0);
155 ASSERT (is_pow2 (lb0->lb_n_buckets));
156 ASSERT (is_pow2 (lb1->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500157 dpo0 = load_balance_get_bucket_i (lb0,
158 (vnet_buffer (p0)->ip.flow_hash &
159 lb0->lb_n_buckets_minus_1));
160 dpo1 = load_balance_get_bucket_i (lb1,
161 (vnet_buffer (p1)->ip.flow_hash &
162 lb1->lb_n_buckets_minus_1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100164 next0 = dpo0->dpoi_next_node;
165 next1 = dpo1->dpoi_next_node;
166
167 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500168 if (PREDICT_FALSE
169 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100170 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100172 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
173 }
Dave Barachd7cb1b52016-12-09 09:52:16 -0500174 if (PREDICT_FALSE
175 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100176 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500177 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100178 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
179 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100180 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
181 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182
Dave Barach75fc8542016-10-11 16:16:02 -0400183 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500184 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Dave Barach75fc8542016-10-11 16:16:02 -0400185 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500186 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187
188 from += 2;
189 to_next += 2;
190 n_left_to_next -= 2;
191 n_left_from -= 2;
192
Dave Barachd7cb1b52016-12-09 09:52:16 -0500193 wrong_next = (next0 != next) + 2 * (next1 != next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 if (PREDICT_FALSE (wrong_next != 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500195 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 switch (wrong_next)
197 {
198 case 1:
199 /* A B A */
200 to_next[-2] = pi1;
201 to_next -= 1;
202 n_left_to_next += 1;
203 vlib_set_next_frame_buffer (vm, node, next0, pi0);
204 break;
205
206 case 2:
207 /* A A B */
208 to_next -= 1;
209 n_left_to_next += 1;
210 vlib_set_next_frame_buffer (vm, node, next1, pi1);
211 break;
212
213 case 3:
214 /* A B C */
215 to_next -= 2;
216 n_left_to_next += 2;
217 vlib_set_next_frame_buffer (vm, node, next0, pi0);
218 vlib_set_next_frame_buffer (vm, node, next1, pi1);
219 if (next0 == next1)
220 {
221 /* A B B */
222 vlib_put_next_frame (vm, node, next, n_left_to_next);
223 next = next1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500224 vlib_get_next_frame (vm, node, next, to_next,
225 n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226 }
227 }
228 }
229 }
Dave Barach75fc8542016-10-11 16:16:02 -0400230
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231 while (n_left_from > 0 && n_left_to_next > 0)
232 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500233 vlib_buffer_t *p0;
234 ip6_header_t *ip0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100235 u32 pi0, lbi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 ip_lookup_next_t next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500237 load_balance_t *lb0;
238 ip6_address_t *dst_addr0;
239 u32 fib_index0, flow_hash_config0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100240 const dpo_id_t *dpo0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241
242 pi0 = from[0];
243 to_next[0] = pi0;
244
245 p0 = vlib_get_buffer (vm, pi0);
246
247 ip0 = vlib_buffer_get_current (p0);
248
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100249 dst_addr0 = &ip0->dst_address;
Damjan Marionaca64c92016-04-13 09:48:56 +0200250
Dave Barachd7cb1b52016-12-09 09:52:16 -0500251 fib_index0 =
252 vec_elt (im->fib_index_by_sw_if_index,
253 vnet_buffer (p0)->sw_if_index[VLIB_RX]);
254 fib_index0 =
255 (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
256 (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
Dave Barachd7cb1b52016-12-09 09:52:16 -0500258 flow_hash_config0 = ip6_fib_get (fib_index0)->flow_hash_config;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100260 lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 lb0 = load_balance_get (lbi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263
Dave Barachd7cb1b52016-12-09 09:52:16 -0500264 vnet_buffer (p0)->ip.flow_hash = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Dave Barachd7cb1b52016-12-09 09:52:16 -0500266 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
267 {
268 flow_hash_config0 = lb0->lb_hash_config;
269 vnet_buffer (p0)->ip.flow_hash =
270 ip6_compute_flow_hash (ip0, flow_hash_config0);
271 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100273 ASSERT (lb0->lb_n_buckets > 0);
274 ASSERT (is_pow2 (lb0->lb_n_buckets));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500275 dpo0 = load_balance_get_bucket_i (lb0,
276 (vnet_buffer (p0)->ip.flow_hash &
277 lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100278 next0 = dpo0->dpoi_next_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
Shwetha57fc8542016-09-27 08:04:05 +0100280 /* Only process the HBH Option Header if explicitly configured to do so */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 if (PREDICT_FALSE
282 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwetha57fc8542016-09-27 08:04:05 +0100283 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500284 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
Shwetha57fc8542016-09-27 08:04:05 +0100285 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
286 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100287 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288
Dave Barach75fc8542016-10-11 16:16:02 -0400289 vlib_increment_combined_counter
Dave Barachd7cb1b52016-12-09 09:52:16 -0500290 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291
292 from += 1;
293 to_next += 1;
294 n_left_to_next -= 1;
295 n_left_from -= 1;
296
297 if (PREDICT_FALSE (next0 != next))
298 {
299 n_left_to_next += 1;
300 vlib_put_next_frame (vm, node, next, n_left_to_next);
301 next = next0;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500302 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303 to_next[0] = pi0;
304 to_next += 1;
305 n_left_to_next -= 1;
306 }
307 }
308
309 vlib_put_next_frame (vm, node, next, n_left_to_next);
310 }
311
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100312 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500313 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100314
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 return frame->n_vectors;
316}
317
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318static void
319ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
320 ip6_main_t * im, u32 fib_index,
321 ip_interface_address_t * a)
322{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500323 ip_lookup_main_t *lm = &im->lookup_main;
324 ip6_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100325 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500326 .fp_len = a->address_length,
327 .fp_proto = FIB_PROTOCOL_IP6,
328 .fp_addr.ip6 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
331 a->neighbor_probe_adj_index = ~0;
332 if (a->address_length < 128)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500333 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100334 fib_node_index_t fei;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335
Dave Barachd7cb1b52016-12-09 09:52:16 -0500336 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 */
337 sw_if_index, ~0, // invalid FIB index
338 1, NULL, // no label stack
339 FIB_ROUTE_PATH_FLAG_NONE);
340 a->neighbor_probe_adj_index = fib_entry_get_adj (fei);
341 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100343 pfx.fp_len = 128;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500345 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100346 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500347 lm->classify_table_index_by_sw_if_index[sw_if_index];
348 if (classify_table_index != (u32) ~ 0)
349 {
350 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100351
Dave Barachd7cb1b52016-12-09 09:52:16 -0500352 dpo_set (&dpo,
353 DPO_CLASSIFY,
354 DPO_PROTO_IP6,
355 classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100356
Dave Barachd7cb1b52016-12-09 09:52:16 -0500357 fib_table_entry_special_dpo_add (fib_index,
358 &pfx,
359 FIB_SOURCE_CLASSIFY,
360 FIB_ENTRY_FLAG_NONE, &dpo);
361 dpo_reset (&dpo);
362 }
363 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100364
Dave Barachd7cb1b52016-12-09 09:52:16 -0500365 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
366 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367}
368
369static void
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100370ip6_del_interface_routes (ip6_main_t * im,
371 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500372 ip6_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500374 fib_prefix_t pfx = {
375 .fp_len = address_length,
376 .fp_proto = FIB_PROTOCOL_IP6,
377 .fp_addr.ip6 = *address,
378 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700379
Dave Barachd7cb1b52016-12-09 09:52:16 -0500380 if (pfx.fp_len < 128)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500382 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100383
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 }
385
Dave Barachd7cb1b52016-12-09 09:52:16 -0500386 pfx.fp_len = 128;
387 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388}
389
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100390void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500391ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100392{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500393 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100395 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100397 /*
398 * enable/disable only on the 1<->0 transition
399 */
400 if (is_enable)
401 {
402 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500403 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100404 }
405 else
406 {
Neale Ranns75152282017-01-09 01:00:45 -0800407 /* The ref count is 0 when an address is removed from an interface that has
408 * no address - this is not a ciritical error */
409 if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
410 0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500411 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100412 }
413
Neale Ranns32e1c012016-11-22 17:07:28 +0000414 if (sw_if_index != 0)
415 ip6_mfib_interface_enable_disable (sw_if_index, is_enable);
416
Damjan Marion8b3191e2016-11-09 19:54:20 +0100417 vnet_feature_enable_disable ("ip6-unicast", "ip6-lookup", sw_if_index,
418 is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100419
Neale Ranns32e1c012016-11-22 17:07:28 +0000420 vnet_feature_enable_disable ("ip6-multicast", "ip6-mfib-forward-lookup",
421 sw_if_index, is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100422
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100423}
424
Neale Rannsdf089a82016-10-02 16:39:06 +0100425/* get first interface address */
426ip6_address_t *
427ip6_interface_first_address (ip6_main_t * im,
428 u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500429 ip_interface_address_t ** result_ia)
Neale Rannsdf089a82016-10-02 16:39:06 +0100430{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500431 ip_lookup_main_t *lm = &im->lookup_main;
432 ip_interface_address_t *ia = 0;
433 ip6_address_t *result = 0;
Neale Rannsdf089a82016-10-02 16:39:06 +0100434
Dave Barachd7cb1b52016-12-09 09:52:16 -0500435 /* *INDENT-OFF* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100436 foreach_ip_interface_address (lm, ia, sw_if_index,
437 1 /* honor unnumbered */,
438 ({
439 ip6_address_t * a = ip_interface_address_get_address (lm, ia);
440 result = a;
441 break;
442 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500443 /* *INDENT-ON* */
Neale Rannsdf089a82016-10-02 16:39:06 +0100444 if (result_ia)
445 *result_ia = result ? ia : 0;
446 return result;
447}
448
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100449clib_error_t *
450ip6_add_del_interface_address (vlib_main_t * vm,
451 u32 sw_if_index,
452 ip6_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700454{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500455 vnet_main_t *vnm = vnet_get_main ();
456 ip6_main_t *im = &ip6_main;
457 ip_lookup_main_t *lm = &im->lookup_main;
458 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459 u32 if_address_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 ip6_address_fib_t ip6_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
462 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +0000463 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
464
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 ip6_addr_fib_init (&ip6_af, address,
466 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
467 vec_add1 (addr_fib, ip6_af);
468
469 {
470 uword elts_before = pool_elts (lm->if_address_pool);
471
472 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500473 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474 if (error)
475 goto done;
476
477 /* Pool did not grow: add duplicate address. */
478 if (elts_before == pool_elts (lm->if_address_pool))
479 goto done;
480 }
481
Dave Barachd7cb1b52016-12-09 09:52:16 -0500482 ip6_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns177bbdc2016-11-15 09:46:51 +0000483
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100484 if (is_del)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500485 ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100486 else
Dave Barachd7cb1b52016-12-09 09:52:16 -0500487 ip6_add_interface_routes (vnm, sw_if_index,
488 im, ip6_af.fib_index,
489 pool_elt_at_index (lm->if_address_pool,
490 if_address_index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491
492 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500493 ip6_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 vec_foreach (cb, im->add_del_interface_address_callbacks)
495 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500496 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497 }
498
Dave Barachd7cb1b52016-12-09 09:52:16 -0500499done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500 vec_free (addr_fib);
501 return error;
502}
503
504clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500505ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500507 ip6_main_t *im = &ip6_main;
508 ip_interface_address_t *ia;
509 ip6_address_t *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700510 u32 is_admin_up, fib_index;
511
512 /* Fill in lookup tables with default table (0). */
513 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
514
Dave Barachd7cb1b52016-12-09 09:52:16 -0500515 vec_validate_init_empty (im->
516 lookup_main.if_address_pool_index_by_sw_if_index,
517 sw_if_index, ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
519 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
520
521 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
522
Dave Barachd7cb1b52016-12-09 09:52:16 -0500523 /* *INDENT-OFF* */
Dave Barach75fc8542016-10-11 16:16:02 -0400524 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 0 /* honor unnumbered */,
526 ({
527 a = ip_interface_address_get_address (&im->lookup_main, ia);
528 if (is_admin_up)
529 ip6_add_interface_routes (vnm, sw_if_index,
530 im, fib_index,
531 ia);
532 else
533 ip6_del_interface_routes (im, fib_index,
534 a, ia->address_length);
535 }));
Dave Barachd7cb1b52016-12-09 09:52:16 -0500536 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
538 return 0;
539}
540
541VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
542
Dave Barachd6534602016-06-14 18:38:02 -0400543/* Built-in ip6 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500544/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100545VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
546{
547 .arc_name = "ip6-unicast",
548 .start_nodes = VNET_FEATURES ("ip6-input"),
549 .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
550};
551
Dave Barachd7cb1b52016-12-09 09:52:16 -0500552VNET_FEATURE_INIT (ip6_flow_classify, static) =
553{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100554 .arc_name = "ip6-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700555 .node_name = "ip6-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100556 .runs_before = VNET_FEATURES ("ip6-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700557};
558
Dave Barachd7cb1b52016-12-09 09:52:16 -0500559VNET_FEATURE_INIT (ip6_inacl, static) =
560{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100561 .arc_name = "ip6-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400562 .node_name = "ip6-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100563 .runs_before = VNET_FEATURES ("ip6-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400564};
565
Dave Barachd7cb1b52016-12-09 09:52:16 -0500566VNET_FEATURE_INIT (ip6_policer_classify, static) =
567{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100568 .arc_name = "ip6-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700569 .node_name = "ip6-policer-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100570 .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700571};
572
Dave Barachd7cb1b52016-12-09 09:52:16 -0500573VNET_FEATURE_INIT (ip6_ipsec, static) =
574{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100575 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400576 .node_name = "ipsec-input-ip6",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100577 .runs_before = VNET_FEATURES ("l2tp-decap"),
Dave Barachd6534602016-06-14 18:38:02 -0400578};
579
Dave Barachd7cb1b52016-12-09 09:52:16 -0500580VNET_FEATURE_INIT (ip6_l2tp, static) =
581{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100582 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400583 .node_name = "l2tp-decap",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100584 .runs_before = VNET_FEATURES ("vpath-input-ip6"),
Dave Barachd6534602016-06-14 18:38:02 -0400585};
586
Dave Barachd7cb1b52016-12-09 09:52:16 -0500587VNET_FEATURE_INIT (ip6_vpath, static) =
588{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100589 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400590 .node_name = "vpath-input-ip6",
John Lo2b81eb82017-01-30 13:12:10 -0500591 .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
592};
593
594VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
595{
596 .arc_name = "ip6-unicast",
597 .node_name = "ip6-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100598 .runs_before = VNET_FEATURES ("ip6-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400599};
600
Dave Barachd7cb1b52016-12-09 09:52:16 -0500601VNET_FEATURE_INIT (ip6_lookup, static) =
602{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100603 .arc_name = "ip6-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400604 .node_name = "ip6-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100605 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400606};
607
Dave Barachd7cb1b52016-12-09 09:52:16 -0500608VNET_FEATURE_INIT (ip6_drop, static) =
609{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100610 .arc_name = "ip6-unicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100611 .node_name = "ip6-drop",
612 .runs_before = 0, /*last feature*/
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100613};
614
Dave Barachd6534602016-06-14 18:38:02 -0400615/* Built-in ip6 multicast rx feature path definition (none now) */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100616VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
617{
618 .arc_name = "ip6-multicast",
619 .start_nodes = VNET_FEATURES ("ip6-input"),
620 .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
621};
622
623VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
624 .arc_name = "ip6-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400625 .node_name = "vpath-input-ip6",
Neale Ranns32e1c012016-11-22 17:07:28 +0000626 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400627};
628
Damjan Marion8b3191e2016-11-09 19:54:20 +0100629VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
630 .arc_name = "ip6-multicast",
Neale Ranns32e1c012016-11-22 17:07:28 +0000631 .node_name = "ip6-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100632 .runs_before = VNET_FEATURES ("ip6-drop"),
Dave Barachd6534602016-06-14 18:38:02 -0400633};
634
Damjan Marion8b3191e2016-11-09 19:54:20 +0100635VNET_FEATURE_INIT (ip6_drop_mc, static) = {
636 .arc_name = "ip6-multicast",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637 .node_name = "ip6-drop",
638 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100639};
Dave Barach5331c722016-08-17 11:54:30 -0400640
641/* Built-in ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100642VNET_FEATURE_ARC_INIT (ip6_output, static) =
643{
644 .arc_name = "ip6-output",
645 .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
646 .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
Dave Barach5331c722016-08-17 11:54:30 -0400647};
648
Matus Fabian08a6f012016-11-15 06:08:51 -0800649VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
650 .arc_name = "ip6-output",
651 .node_name = "ipsec-output-ip6",
652 .runs_before = VNET_FEATURES ("interface-output"),
653};
654
Damjan Marion8b3191e2016-11-09 19:54:20 +0100655VNET_FEATURE_INIT (ip6_interface_output, static) = {
656 .arc_name = "ip6-output",
657 .node_name = "interface-output",
658 .runs_before = 0, /* not before any other features */
659};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500660/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -0400661
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500663ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100665 vnet_feature_enable_disable ("ip6-unicast", "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-multicast", "ip6-drop", sw_if_index,
669 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Damjan Marion8b3191e2016-11-09 19:54:20 +0100671 vnet_feature_enable_disable ("ip6-output", "interface-output", sw_if_index,
672 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673
Ed Warnickecb9cada2015-12-08 15:45:58 -0700674 return /* no error */ 0;
675}
676
677VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_sw_interface_add_del);
678
Damjan Marionaca64c92016-04-13 09:48:56 +0200679static uword
680ip6_lookup (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500681 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200682{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100683 return ip6_lookup_inline (vm, node, frame);
Damjan Marionaca64c92016-04-13 09:48:56 +0200684}
685
Dave Barachd7cb1b52016-12-09 09:52:16 -0500686static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100687
Dave Barachd7cb1b52016-12-09 09:52:16 -0500688/* *INDENT-OFF* */
689VLIB_REGISTER_NODE (ip6_lookup_node) =
690{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 .function = ip6_lookup,
692 .name = "ip6-lookup",
693 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100694 .format_trace = format_ip6_lookup_trace,
Ole Troanf0f85222016-06-14 21:12:32 +0200695 .n_next_nodes = IP6_LOOKUP_N_NEXT,
Damjan Marionb2707892016-04-13 11:21:07 +0200696 .next_nodes = IP6_LOOKUP_NEXT_NODES,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500698/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699
Dave Barachd7cb1b52016-12-09 09:52:16 -0500700VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
Damjan Marion1c80e832016-05-11 23:07:18 +0200701
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100702always_inline uword
703ip6_load_balance (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500704 vlib_node_runtime_t * node, vlib_frame_t * frame)
Damjan Marionaca64c92016-04-13 09:48:56 +0200705{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
707 u32 n_left_from, n_left_to_next, *from, *to_next;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100708 ip_lookup_next_t next;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500709 u32 cpu_index = os_get_cpu_number ();
710 ip6_main_t *im = &ip6_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100711
712 from = vlib_frame_vector_args (frame);
713 n_left_from = frame->n_vectors;
714 next = node->cached_next_index;
715
716 if (node->flags & VLIB_NODE_FLAG_TRACE)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500717 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100718
719 while (n_left_from > 0)
720 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500721 vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100722
Dave Barach75fc8542016-10-11 16:16:02 -0400723
Neale Ranns2be95c12016-11-19 13:50:04 +0000724 while (n_left_from >= 4 && n_left_to_next >= 2)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500725 {
726 ip_lookup_next_t next0, next1;
727 const load_balance_t *lb0, *lb1;
728 vlib_buffer_t *p0, *p1;
729 u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
730 const ip6_header_t *ip0, *ip1;
731 const dpo_id_t *dpo0, *dpo1;
Neale Ranns2be95c12016-11-19 13:50:04 +0000732
Dave Barachd7cb1b52016-12-09 09:52:16 -0500733 /* Prefetch next iteration. */
734 {
735 vlib_buffer_t *p2, *p3;
Neale Ranns2be95c12016-11-19 13:50:04 +0000736
Dave Barachd7cb1b52016-12-09 09:52:16 -0500737 p2 = vlib_get_buffer (vm, from[2]);
738 p3 = vlib_get_buffer (vm, from[3]);
Neale Ranns2be95c12016-11-19 13:50:04 +0000739
Dave Barachd7cb1b52016-12-09 09:52:16 -0500740 vlib_prefetch_buffer_header (p2, STORE);
741 vlib_prefetch_buffer_header (p3, STORE);
Neale Ranns2be95c12016-11-19 13:50:04 +0000742
Dave Barachd7cb1b52016-12-09 09:52:16 -0500743 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
744 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
745 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000746
Dave Barachd7cb1b52016-12-09 09:52:16 -0500747 pi0 = to_next[0] = from[0];
748 pi1 = to_next[1] = from[1];
Neale Ranns2be95c12016-11-19 13:50:04 +0000749
Dave Barachd7cb1b52016-12-09 09:52:16 -0500750 from += 2;
751 n_left_from -= 2;
752 to_next += 2;
753 n_left_to_next -= 2;
Neale Ranns2be95c12016-11-19 13:50:04 +0000754
Dave Barachd7cb1b52016-12-09 09:52:16 -0500755 p0 = vlib_get_buffer (vm, pi0);
756 p1 = vlib_get_buffer (vm, pi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000757
Dave Barachd7cb1b52016-12-09 09:52:16 -0500758 ip0 = vlib_buffer_get_current (p0);
759 ip1 = vlib_buffer_get_current (p1);
760 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
761 lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Neale Ranns2be95c12016-11-19 13:50:04 +0000762
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 lb0 = load_balance_get (lbi0);
764 lb1 = load_balance_get (lbi1);
Neale Ranns2be95c12016-11-19 13:50:04 +0000765
Dave Barachd7cb1b52016-12-09 09:52:16 -0500766 /*
767 * this node is for via FIBs we can re-use the hash value from the
768 * to node if present.
769 * We don't want to use the same hash value at each level in the recursion
770 * graph as that would lead to polarisation
771 */
772 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
773 hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
Neale Ranns2be95c12016-11-19 13:50:04 +0000774
Dave Barachd7cb1b52016-12-09 09:52:16 -0500775 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
776 {
777 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
778 {
779 hc0 = vnet_buffer (p0)->ip.flow_hash =
780 vnet_buffer (p0)->ip.flow_hash >> 1;
781 }
782 else
783 {
784 hc0 = vnet_buffer (p0)->ip.flow_hash =
785 ip6_compute_flow_hash (ip0, hc0);
786 }
787 }
788 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
789 {
790 if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
791 {
792 hc1 = vnet_buffer (p1)->ip.flow_hash =
793 vnet_buffer (p1)->ip.flow_hash >> 1;
794 }
795 else
796 {
797 hc1 = vnet_buffer (p1)->ip.flow_hash =
798 ip6_compute_flow_hash (ip1, hc1);
799 }
800 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000801
Dave Barachd7cb1b52016-12-09 09:52:16 -0500802 dpo0 =
803 load_balance_get_bucket_i (lb0,
804 hc0 & (lb0->lb_n_buckets_minus_1));
805 dpo1 =
806 load_balance_get_bucket_i (lb1,
807 hc1 & (lb1->lb_n_buckets_minus_1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000808
Dave Barachd7cb1b52016-12-09 09:52:16 -0500809 next0 = dpo0->dpoi_next_node;
810 next1 = dpo1->dpoi_next_node;
Neale Ranns2be95c12016-11-19 13:50:04 +0000811
Dave Barachd7cb1b52016-12-09 09:52:16 -0500812 /* Only process the HBH Option Header if explicitly configured to do so */
813 if (PREDICT_FALSE
814 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
815 {
816 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
817 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
818 }
819 /* Only process the HBH Option Header if explicitly configured to do so */
820 if (PREDICT_FALSE
821 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
822 {
823 next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
824 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next1;
825 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000826
Dave Barachd7cb1b52016-12-09 09:52:16 -0500827 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
828 vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000829
Dave Barachd7cb1b52016-12-09 09:52:16 -0500830 vlib_increment_combined_counter
831 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
832 vlib_increment_combined_counter
833 (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
Neale Ranns2be95c12016-11-19 13:50:04 +0000834
Dave Barachd7cb1b52016-12-09 09:52:16 -0500835 vlib_validate_buffer_enqueue_x2 (vm, node, next,
836 to_next, n_left_to_next,
837 pi0, pi1, next0, next1);
838 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000839
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100840 while (n_left_from > 0 && n_left_to_next > 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -0500841 {
842 ip_lookup_next_t next0;
843 const load_balance_t *lb0;
844 vlib_buffer_t *p0;
845 u32 pi0, lbi0, hc0;
846 const ip6_header_t *ip0;
847 const dpo_id_t *dpo0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100848
Dave Barachd7cb1b52016-12-09 09:52:16 -0500849 pi0 = from[0];
850 to_next[0] = pi0;
851 from += 1;
852 to_next += 1;
853 n_left_to_next -= 1;
854 n_left_from -= 1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100855
Dave Barachd7cb1b52016-12-09 09:52:16 -0500856 p0 = vlib_get_buffer (vm, pi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100857
Dave Barachd7cb1b52016-12-09 09:52:16 -0500858 ip0 = vlib_buffer_get_current (p0);
859 lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100860
Dave Barachd7cb1b52016-12-09 09:52:16 -0500861 lb0 = load_balance_get (lbi0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100862
Dave Barachd7cb1b52016-12-09 09:52:16 -0500863 hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
864 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
865 {
866 if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
867 {
868 hc0 = vnet_buffer (p0)->ip.flow_hash =
869 vnet_buffer (p0)->ip.flow_hash >> 1;
870 }
871 else
872 {
873 hc0 = vnet_buffer (p0)->ip.flow_hash =
874 ip6_compute_flow_hash (ip0, hc0);
875 }
876 }
877 dpo0 =
878 load_balance_get_bucket_i (lb0,
879 hc0 & (lb0->lb_n_buckets_minus_1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100880
Dave Barachd7cb1b52016-12-09 09:52:16 -0500881 next0 = dpo0->dpoi_next_node;
882 vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
Neale Ranns2be95c12016-11-19 13:50:04 +0000883
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884 /* Only process the HBH Option Header if explicitly configured to do so */
885 if (PREDICT_FALSE
886 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
887 {
888 next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
889 (ip_lookup_next_t) IP6_LOOKUP_NEXT_HOP_BY_HOP : next0;
890 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000891
Dave Barachd7cb1b52016-12-09 09:52:16 -0500892 vlib_increment_combined_counter
893 (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100894
Dave Barachd7cb1b52016-12-09 09:52:16 -0500895 vlib_validate_buffer_enqueue_x1 (vm, node, next,
896 to_next, n_left_to_next,
897 pi0, next0);
898 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100899
900 vlib_put_next_frame (vm, node, next, n_left_to_next);
901 }
902
903 return frame->n_vectors;
Damjan Marionaca64c92016-04-13 09:48:56 +0200904}
905
Dave Barachd7cb1b52016-12-09 09:52:16 -0500906/* *INDENT-OFF* */
907VLIB_REGISTER_NODE (ip6_load_balance_node) =
908{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100909 .function = ip6_load_balance,
910 .name = "ip6-load-balance",
Damjan Marionaca64c92016-04-13 09:48:56 +0200911 .vector_size = sizeof (u32),
Ole Troanf0f85222016-06-14 21:12:32 +0200912 .sibling_of = "ip6-lookup",
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100913 .format_trace = format_ip6_lookup_trace,
Damjan Marionaca64c92016-04-13 09:48:56 +0200914};
Dave Barachd7cb1b52016-12-09 09:52:16 -0500915/* *INDENT-ON* */
Damjan Marionaca64c92016-04-13 09:48:56 +0200916
Dave Barachd7cb1b52016-12-09 09:52:16 -0500917VLIB_NODE_FUNCTION_MULTIARCH (ip6_load_balance_node, ip6_load_balance);
Damjan Marion1c80e832016-05-11 23:07:18 +0200918
Dave Barachd7cb1b52016-12-09 09:52:16 -0500919typedef struct
920{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921 /* Adjacency taken. */
922 u32 adj_index;
923 u32 flow_hash;
John Lo2d343742016-01-19 17:27:17 -0500924 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700925
926 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500927 u8 packet_data[128 - 1 * sizeof (u32)];
928}
929ip6_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700930
John Lo2b81eb82017-01-30 13:12:10 -0500931u8 *
Dave Barachd7cb1b52016-12-09 09:52:16 -0500932format_ip6_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700933{
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100934 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
935 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500936 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100937 uword indent = format_get_indent (s);
938
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939 s = format (s, "%U%U",
940 format_white_space, indent,
941 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100942 return s;
943}
944
Dave Barachd7cb1b52016-12-09 09:52:16 -0500945static u8 *
946format_ip6_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100947{
948 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
949 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500950 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 uword indent = format_get_indent (s);
952
John Loac8146c2016-09-27 17:44:02 -0400953 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500954 t->fib_index, t->adj_index, t->flow_hash);
955 s = format (s, "\n%U%U",
956 format_white_space, indent,
957 format_ip6_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100958 return s;
959}
Pierre Pfister0febaf12016-06-08 12:23:21 +0100960
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961
Dave Barachd7cb1b52016-12-09 09:52:16 -0500962static u8 *
963format_ip6_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100964{
965 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
966 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500967 ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
968 vnet_main_t *vnm = vnet_get_main ();
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100969 uword indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700970
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100971 s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500972 t->fib_index, t->adj_index, format_ip_adjacency,
973 t->adj_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +0100974 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500975 format_white_space, indent,
976 format_ip_adjacency_packet_data,
977 vnm, t->adj_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978 return s;
979}
980
981/* Common trace function for all ip6-forward next nodes. */
982void
983ip6_forward_next_trace (vlib_main_t * vm,
984 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500985 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500987 u32 *from, n_left;
988 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700989
990 n_left = frame->n_vectors;
991 from = vlib_frame_vector_args (frame);
Pierre Pfister0febaf12016-06-08 12:23:21 +0100992
Ed Warnickecb9cada2015-12-08 15:45:58 -0700993 while (n_left >= 4)
994 {
995 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500996 vlib_buffer_t *b0, *b1;
997 ip6_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700998
999 /* Prefetch next iteration. */
1000 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1001 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1002
1003 bi0 = from[0];
1004 bi1 = from[1];
1005
1006 b0 = vlib_get_buffer (vm, bi0);
1007 b1 = vlib_get_buffer (vm, bi1);
1008
1009 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1010 {
1011 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1012 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001013 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1014 t0->fib_index =
1015 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1016 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1017 vec_elt (im->fib_index_by_sw_if_index,
1018 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001019
Damjan Marionf1213b82016-03-13 02:22:06 +01001020 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001021 vlib_buffer_get_current (b0),
1022 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 }
1024 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1025 {
1026 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1027 t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1029 t1->fib_index =
1030 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1031 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1032 vec_elt (im->fib_index_by_sw_if_index,
1033 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001034
Damjan Marionf1213b82016-03-13 02:22:06 +01001035 clib_memcpy (t1->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001036 vlib_buffer_get_current (b1),
1037 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038 }
1039 from += 2;
1040 n_left -= 2;
1041 }
1042
1043 while (n_left >= 1)
1044 {
1045 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001046 vlib_buffer_t *b0;
1047 ip6_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048
1049 bi0 = from[0];
1050
1051 b0 = vlib_get_buffer (vm, bi0);
1052
1053 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1054 {
1055 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1056 t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Dave Barachd7cb1b52016-12-09 09:52:16 -05001057 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1058 t0->fib_index =
1059 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1060 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1061 vec_elt (im->fib_index_by_sw_if_index,
1062 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001063
Damjan Marionf1213b82016-03-13 02:22:06 +01001064 clib_memcpy (t0->packet_data,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001065 vlib_buffer_get_current (b0),
1066 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067 }
1068 from += 1;
1069 n_left -= 1;
1070 }
1071}
1072
1073static uword
1074ip6_drop_or_punt (vlib_main_t * vm,
1075 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001076 vlib_frame_t * frame, ip6_error_t error_code)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001078 u32 *buffers = vlib_frame_vector_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079 uword n_packets = frame->n_vectors;
1080
Dave Barachd7cb1b52016-12-09 09:52:16 -05001081 vlib_error_drop_buffers (vm, node, buffers,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 /* stride */ 1,
1083 n_packets,
1084 /* next */ 0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085 ip6_input_node.index, error_code);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086
1087 if (node->flags & VLIB_NODE_FLAG_TRACE)
1088 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1089
1090 return n_packets;
1091}
1092
1093static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001094ip6_drop (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1095{
1096 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1097}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098
1099static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001100ip6_punt (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1101{
1102 return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1103}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104
Dave Barachd7cb1b52016-12-09 09:52:16 -05001105/* *INDENT-OFF* */
1106VLIB_REGISTER_NODE (ip6_drop_node, static) =
1107{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108 .function = ip6_drop,
1109 .name = "ip6-drop",
1110 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001113 .next_nodes =
1114 {
1115 [0] = "error-drop",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001117/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001118
Dave Barachd7cb1b52016-12-09 09:52:16 -05001119VLIB_NODE_FUNCTION_MULTIARCH (ip6_drop_node, ip6_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001120
Dave Barachd7cb1b52016-12-09 09:52:16 -05001121/* *INDENT-OFF* */
1122VLIB_REGISTER_NODE (ip6_punt_node, static) =
1123{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124 .function = ip6_punt,
1125 .name = "ip6-punt",
1126 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 .n_next_nodes = 1,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001129 .next_nodes =
1130 {
1131 [0] = "error-punt",},
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001133/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001134
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135VLIB_NODE_FUNCTION_MULTIARCH (ip6_punt_node, ip6_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001136
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137/* Compute TCP/UDP/ICMP6 checksum in software. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138u16
1139ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1140 ip6_header_t * ip0, int *bogus_lengthp)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141{
1142 ip_csum_t sum0;
1143 u16 sum16, payload_length_host_byte_order;
1144 u32 i, n_this_buffer, n_bytes_left;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001145 u32 headers_size = sizeof (ip0[0]);
1146 void *data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147
Dave Barachd7cb1b52016-12-09 09:52:16 -05001148 ASSERT (bogus_lengthp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 *bogus_lengthp = 0;
1150
1151 /* Initialize checksum with ip header. */
1152 sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1153 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1154 data_this_buffer = (void *) (ip0 + 1);
Dave Barach75fc8542016-10-11 16:16:02 -04001155
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1157 {
1158 sum0 = ip_csum_with_carry (sum0,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001159 clib_mem_unaligned (&ip0->
1160 src_address.as_uword[i],
1161 uword));
1162 sum0 =
1163 ip_csum_with_carry (sum0,
1164 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
1165 uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166 }
1167
1168 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001169 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001171 u32 skip_bytes;
1172 ip6_hop_by_hop_ext_t *ext_hdr =
1173 (ip6_hop_by_hop_ext_t *) data_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
1175 /* validate really icmp6 next */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001176 ASSERT (ext_hdr->next_hdr == IP_PROTOCOL_ICMP6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001177
Dave Barachd7cb1b52016-12-09 09:52:16 -05001178 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1179 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
Dave Barach75fc8542016-10-11 16:16:02 -04001180
Dave Barachd7cb1b52016-12-09 09:52:16 -05001181 payload_length_host_byte_order -= skip_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001182 headers_size += skip_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001183 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184
1185 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001186 if (p0 && n_this_buffer + headers_size > p0->current_length)
1187 n_this_buffer =
1188 p0->current_length >
1189 headers_size ? p0->current_length - headers_size : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190 while (1)
1191 {
1192 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1193 n_bytes_left -= n_this_buffer;
1194 if (n_bytes_left == 0)
1195 break;
1196
1197 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198 {
1199 *bogus_lengthp = 1;
1200 return 0xfefe;
1201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202 p0 = vlib_get_buffer (vm, p0->next_buffer);
1203 data_this_buffer = vlib_buffer_get_current (p0);
1204 n_this_buffer = p0->current_length;
1205 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001206
Dave Barachd7cb1b52016-12-09 09:52:16 -05001207 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208
1209 return sum16;
1210}
1211
Dave Barachd7cb1b52016-12-09 09:52:16 -05001212u32
1213ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 ip6_header_t *ip0 = vlib_buffer_get_current (p0);
1216 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217 u16 sum16;
1218 int bogus_length;
1219
1220 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1221 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1222 || ip0->protocol == IP_PROTOCOL_ICMP6
1223 || ip0->protocol == IP_PROTOCOL_UDP
Dave Barachd7cb1b52016-12-09 09:52:16 -05001224 || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001225
1226 udp0 = (void *) (ip0 + 1);
1227 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1228 {
1229 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1230 | IP_BUFFER_L4_CHECKSUM_CORRECT);
1231 return p0->flags;
1232 }
1233
1234 sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1235
1236 p0->flags |= (IP_BUFFER_L4_CHECKSUM_COMPUTED
1237 | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1238
1239 return p0->flags;
1240}
1241
Shwethab78292e2016-09-13 11:51:00 +01001242/* ip6_locate_header
1243 *
1244 * This function is to search for the header specified by the find_hdr number.
1245 * 1. If the find_hdr < 0 then it finds and returns the protocol number and
1246 * offset stored in *offset of the transport or ESP header in the chain if
1247 * found.
1248 * 2. If a header with find_hdr > 0 protocol number is found then the
1249 * offset is stored in *offset and protocol number of the header is
1250 * returned.
1251 * 3. If find_hdr header is not found or packet is malformed or
1252 * it is a non-first fragment -1 is returned.
1253 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001254always_inline int
1255ip6_locate_header (vlib_buffer_t * p0,
1256 ip6_header_t * ip0, int find_hdr, u32 * offset)
Shwethab78292e2016-09-13 11:51:00 +01001257{
1258 u8 next_proto = ip0->protocol;
1259 u8 *next_header;
1260 u8 done = 0;
1261 u32 cur_offset;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001262 u8 *temp_nxthdr = 0;
Shwethab78292e2016-09-13 11:51:00 +01001263 u32 exthdr_len = 0;
1264
Dave Barachd7cb1b52016-12-09 09:52:16 -05001265 next_header = ip6_next_header (ip0);
1266 cur_offset = sizeof (ip6_header_t);
1267 while (1)
Shwethab78292e2016-09-13 11:51:00 +01001268 {
1269 done = (next_proto == find_hdr);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001270 if (PREDICT_FALSE
1271 (next_header >=
1272 (u8 *) vlib_buffer_get_current (p0) + p0->current_length))
Shwethab78292e2016-09-13 11:51:00 +01001273 {
1274 //A malicious packet could set an extension header with a too big size
Dave Barachd7cb1b52016-12-09 09:52:16 -05001275 return (-1);
Shwethab78292e2016-09-13 11:51:00 +01001276 }
1277 if (done)
1278 break;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001279 if ((!ip6_ext_hdr (next_proto)) || next_proto == IP_PROTOCOL_IP6_NONXT)
Shwethab78292e2016-09-13 11:51:00 +01001280 {
1281 if (find_hdr < 0)
1282 break;
1283 return -1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001284 }
Shwethab78292e2016-09-13 11:51:00 +01001285 if (next_proto == IP_PROTOCOL_IPV6_FRAGMENTATION)
1286 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) next_header;
1288 u16 frag_off = ip6_frag_hdr_offset (frag_hdr);
1289 /* Non first fragment return -1 */
Shwethab78292e2016-09-13 11:51:00 +01001290 if (frag_off)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001291 return (-1);
1292 exthdr_len = sizeof (ip6_frag_hdr_t);
1293 temp_nxthdr = next_header + exthdr_len;
Shwethab78292e2016-09-13 11:51:00 +01001294 }
1295 else if (next_proto == IP_PROTOCOL_IPSEC_AH)
1296 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001297 exthdr_len =
1298 ip6_ext_authhdr_len (((ip6_ext_header_t *) next_header));
Shwethab78292e2016-09-13 11:51:00 +01001299 temp_nxthdr = next_header + exthdr_len;
1300 }
1301 else
1302 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001303 exthdr_len =
1304 ip6_ext_header_len (((ip6_ext_header_t *) next_header));
Shwethab78292e2016-09-13 11:51:00 +01001305 temp_nxthdr = next_header + exthdr_len;
1306 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001307 next_proto = ((ip6_ext_header_t *) next_header)->next_hdr;
1308 next_header = temp_nxthdr;
1309 cur_offset += exthdr_len;
Shwethab78292e2016-09-13 11:51:00 +01001310 }
1311
1312 *offset = cur_offset;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001313 return (next_proto);
Shwethab78292e2016-09-13 11:51:00 +01001314}
1315
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001317ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001319 ip6_main_t *im = &ip6_main;
1320 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001321 ip_local_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001322 u32 *from, *to_next, n_left_from, n_left_to_next;
1323 vlib_node_runtime_t *error_node =
1324 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325
1326 from = vlib_frame_vector_args (frame);
1327 n_left_from = frame->n_vectors;
1328 next_index = node->cached_next_index;
Dave Barach75fc8542016-10-11 16:16:02 -04001329
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330 if (node->flags & VLIB_NODE_FLAG_TRACE)
1331 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1332
1333 while (n_left_from > 0)
1334 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001335 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001336
1337 while (n_left_from >= 4 && n_left_to_next >= 2)
1338 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001339 vlib_buffer_t *p0, *p1;
1340 ip6_header_t *ip0, *ip1;
1341 udp_header_t *udp0, *udp1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342 u32 pi0, ip_len0, udp_len0, flags0, next0;
1343 u32 pi1, ip_len1, udp_len1, flags1, next1;
1344 i32 len_diff0, len_diff1;
1345 u8 error0, type0, good_l4_checksum0;
1346 u8 error1, type1, good_l4_checksum1;
Shwethab78292e2016-09-13 11:51:00 +01001347 u32 udp_offset0, udp_offset1;
Dave Barach75fc8542016-10-11 16:16:02 -04001348
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349 pi0 = to_next[0] = from[0];
1350 pi1 = to_next[1] = from[1];
1351 from += 2;
1352 n_left_from -= 2;
1353 to_next += 2;
1354 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04001355
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356 p0 = vlib_get_buffer (vm, pi0);
1357 p1 = vlib_get_buffer (vm, pi1);
1358
1359 ip0 = vlib_buffer_get_current (p0);
1360 ip1 = vlib_buffer_get_current (p1);
1361
Filip Tehlarb601f222017-01-02 10:22:56 +01001362 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1363 vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1364
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1366 type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1367
1368 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1369 next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1370
1371 flags0 = p0->flags;
1372 flags1 = p1->flags;
1373
1374 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1375 good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001376 len_diff0 = 0;
1377 len_diff1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001378
Shwethab78292e2016-09-13 11:51:00 +01001379 /* Skip HBH local processing */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001380 if (PREDICT_FALSE
1381 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwethab78292e2016-09-13 11:51:00 +01001382 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001383 ip6_hop_by_hop_ext_t *ext_hdr =
1384 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
Shwethab78292e2016-09-13 11:51:00 +01001385 next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1386 type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1387 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001388 if (PREDICT_FALSE
1389 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwethab78292e2016-09-13 11:51:00 +01001390 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001391 ip6_hop_by_hop_ext_t *ext_hdr =
1392 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
Shwethab78292e2016-09-13 11:51:00 +01001393 next1 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1394 type1 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1395 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001396 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1397 IP_PROTOCOL_UDP,
1398 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001399 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001400 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001401 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001402 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1403 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001404 /* Verify UDP length. */
1405 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1406 udp_len0 = clib_net_to_host_u16 (udp0->length);
1407 len_diff0 = ip_len0 - udp_len0;
1408 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001409 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1410 IP_PROTOCOL_UDP,
1411 &udp_offset1)))
Shwethab78292e2016-09-13 11:51:00 +01001412 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001413 udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
Shwethab78292e2016-09-13 11:51:00 +01001414 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001415 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1416 && udp1->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001417 /* Verify UDP length. */
1418 ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1419 udp_len1 = clib_net_to_host_u16 (udp1->length);
1420 len_diff1 = ip_len1 - udp_len1;
1421 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001422
1423 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1424 good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1425
Ed Warnickecb9cada2015-12-08 15:45:58 -07001426 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1427 len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1428
1429 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001430 && !good_l4_checksum0
1431 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001432 {
1433 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1434 good_l4_checksum0 =
1435 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1436 }
1437 if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001438 && !good_l4_checksum1
1439 && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001440 {
1441 flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1442 good_l4_checksum1 =
1443 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1444 }
1445
1446 error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1447
1448 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1449 error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1450
Dave Barachd7cb1b52016-12-09 09:52:16 -05001451 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1452 IP6_ERROR_UDP_CHECKSUM);
1453 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1454 IP6_ERROR_ICMP_CHECKSUM);
1455 error0 =
1456 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1457 error1 =
1458 (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001459
1460 /* Drop packets from unroutable hosts. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001461 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001462 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1463 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001464 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001465 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301466 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001467 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001468 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001469 if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1470 type1 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001471 !ip6_address_is_link_local_unicast (&ip1->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001472 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301473 error1 = (!ip6_urpf_loose_check (im, p1, ip1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001474 ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001475 }
1476
Dave Barachd7cb1b52016-12-09 09:52:16 -05001477 next0 =
1478 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1479 next1 =
1480 error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001481
1482 p0->error = error_node->errors[error0];
1483 p1->error = error_node->errors[error1];
1484
1485 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1486 to_next, n_left_to_next,
1487 pi0, pi1, next0, next1);
1488 }
1489
1490 while (n_left_from > 0 && n_left_to_next > 0)
1491 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001492 vlib_buffer_t *p0;
1493 ip6_header_t *ip0;
1494 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001495 u32 pi0, ip_len0, udp_len0, flags0, next0;
1496 i32 len_diff0;
1497 u8 error0, type0, good_l4_checksum0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001498 u32 udp_offset0;
Dave Barach75fc8542016-10-11 16:16:02 -04001499
Ed Warnickecb9cada2015-12-08 15:45:58 -07001500 pi0 = to_next[0] = from[0];
1501 from += 1;
1502 n_left_from -= 1;
1503 to_next += 1;
1504 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04001505
Ed Warnickecb9cada2015-12-08 15:45:58 -07001506 p0 = vlib_get_buffer (vm, pi0);
1507
1508 ip0 = vlib_buffer_get_current (p0);
1509
Filip Tehlarb601f222017-01-02 10:22:56 +01001510 vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1511
Ed Warnickecb9cada2015-12-08 15:45:58 -07001512 type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1513 next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1514
1515 flags0 = p0->flags;
1516
1517 good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
Shwethab78292e2016-09-13 11:51:00 +01001518 len_diff0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001519
Shwethab78292e2016-09-13 11:51:00 +01001520 /* Skip HBH local processing */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001521 if (PREDICT_FALSE
1522 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
Shwethab78292e2016-09-13 11:51:00 +01001523 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001524 ip6_hop_by_hop_ext_t *ext_hdr =
1525 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
Shwethab78292e2016-09-13 11:51:00 +01001526 next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1527 type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1528 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05001529 if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1530 IP_PROTOCOL_UDP,
1531 &udp_offset0)))
Shwethab78292e2016-09-13 11:51:00 +01001532 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001533 udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
Shwethab78292e2016-09-13 11:51:00 +01001534 /* Don't verify UDP checksum for packets with explicit zero checksum. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001535 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1536 && udp0->checksum == 0;
Shwethab78292e2016-09-13 11:51:00 +01001537 /* Verify UDP length. */
1538 ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1539 udp_len0 = clib_net_to_host_u16 (udp0->length);
1540 len_diff0 = ip_len0 - udp_len0;
1541 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542
1543 good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544 len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1545
1546 if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
Dave Barachd7cb1b52016-12-09 09:52:16 -05001547 && !good_l4_checksum0
1548 && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001549 {
1550 flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1551 good_l4_checksum0 =
1552 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1553 }
1554
1555 error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1556
1557 error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1558
Dave Barachd7cb1b52016-12-09 09:52:16 -05001559 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1560 IP6_ERROR_UDP_CHECKSUM);
1561 ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1562 IP6_ERROR_ICMP_CHECKSUM);
1563 error0 =
1564 (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001565
Dave Barachd7cb1b52016-12-09 09:52:16 -05001566 /* If this is a neighbor solicitation (ICMP), skip source RPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001567 if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1568 type0 != IP_BUILTIN_PROTOCOL_ICMP &&
Dave Barachd7cb1b52016-12-09 09:52:16 -05001569 !ip6_address_is_link_local_unicast (&ip0->src_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001570 {
AkshayaNadahalli8ea6d712017-02-07 23:59:54 +05301571 error0 = (!ip6_urpf_loose_check (im, p0, ip0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001572 ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001573 }
1574
Dave Barachd7cb1b52016-12-09 09:52:16 -05001575 next0 =
1576 error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001577
1578 p0->error = error_node->errors[error0];
1579
1580 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1581 to_next, n_left_to_next,
1582 pi0, next0);
1583 }
Dave Barach75fc8542016-10-11 16:16:02 -04001584
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1586 }
1587
1588 return frame->n_vectors;
1589}
1590
Dave Barachd7cb1b52016-12-09 09:52:16 -05001591/* *INDENT-OFF* */
1592VLIB_REGISTER_NODE (ip6_local_node, static) =
1593{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594 .function = ip6_local,
1595 .name = "ip6-local",
1596 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001597 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001598 .n_next_nodes = IP_LOCAL_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001599 .next_nodes =
1600 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001601 [IP_LOCAL_NEXT_DROP] = "error-drop",
1602 [IP_LOCAL_NEXT_PUNT] = "error-punt",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001603 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1604 [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1605 },
1606};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001607/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608
Dave Barachd7cb1b52016-12-09 09:52:16 -05001609VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
Damjan Marion1c80e832016-05-11 23:07:18 +02001610
Dave Barachd7cb1b52016-12-09 09:52:16 -05001611void
1612ip6_register_protocol (u32 protocol, u32 node_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001613{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001614 vlib_main_t *vm = vlib_get_main ();
1615 ip6_main_t *im = &ip6_main;
1616 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001617
1618 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001619 lm->local_next_by_ip_protocol[protocol] =
1620 vlib_node_add_next (vm, ip6_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001621}
1622
Dave Barachd7cb1b52016-12-09 09:52:16 -05001623typedef enum
1624{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001625 IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
John Lod1f5d042016-04-12 18:20:39 -04001626 IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001627 IP6_DISCOVER_NEIGHBOR_N_NEXT,
1628} ip6_discover_neighbor_next_t;
1629
Dave Barachd7cb1b52016-12-09 09:52:16 -05001630typedef enum
1631{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001632 IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1633 IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
Pierre Pfisterd076f192016-06-22 12:58:30 +01001634 IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001635} ip6_discover_neighbor_error_t;
1636
1637static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001638ip6_discover_neighbor_inline (vlib_main_t * vm,
1639 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001640 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001641{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001642 vnet_main_t *vnm = vnet_get_main ();
1643 ip6_main_t *im = &ip6_main;
1644 ip_lookup_main_t *lm = &im->lookup_main;
1645 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 uword n_left_from, n_left_to_next_drop;
1647 static f64 time_last_seed_change = -1e100;
1648 static u32 hash_seeds[3];
Dave Barach75fc8542016-10-11 16:16:02 -04001649 static uword hash_bitmap[256 / BITS (uword)];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001650 f64 time_now;
1651 int bogus_length;
1652
1653 if (node->flags & VLIB_NODE_FLAG_TRACE)
1654 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1655
1656 time_now = vlib_time_now (vm);
1657 if (time_now - time_last_seed_change > 1e-3)
1658 {
1659 uword i;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001660 u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1661 sizeof (hash_seeds));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001662 for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1663 hash_seeds[i] = r[i];
1664
1665 /* Mark all hash keys as been not-seen before. */
1666 for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1667 hash_bitmap[i] = 0;
1668
1669 time_last_seed_change = time_now;
1670 }
1671
1672 from = vlib_frame_vector_args (frame);
1673 n_left_from = frame->n_vectors;
1674
1675 while (n_left_from > 0)
1676 {
1677 vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1678 to_next_drop, n_left_to_next_drop);
1679
1680 while (n_left_from > 0 && n_left_to_next_drop > 0)
1681 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001682 vlib_buffer_t *p0;
1683 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001684 u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1685 uword bm0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001686 ip_adjacency_t *adj0;
1687 vnet_hw_interface_t *hw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001688 u32 next0;
1689
1690 pi0 = from[0];
1691
1692 p0 = vlib_get_buffer (vm, pi0);
1693
1694 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1695
1696 ip0 = vlib_buffer_get_current (p0);
1697
1698 adj0 = ip_get_adjacency (lm, adj_index0);
1699
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001700 if (!is_glean)
1701 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001702 ip0->dst_address.as_u64[0] =
1703 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1704 ip0->dst_address.as_u64[1] =
1705 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001706 }
Pierre Pfister1dabaaf2016-04-25 14:15:15 +01001707
Ed Warnickecb9cada2015-12-08 15:45:58 -07001708 a0 = hash_seeds[0];
1709 b0 = hash_seeds[1];
1710 c0 = hash_seeds[2];
1711
1712 sw_if_index0 = adj0->rewrite_header.sw_if_index;
1713 vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1714
1715 a0 ^= sw_if_index0;
1716 b0 ^= ip0->dst_address.as_u32[0];
1717 c0 ^= ip0->dst_address.as_u32[1];
1718
1719 hash_v3_mix32 (a0, b0, c0);
1720
1721 b0 ^= ip0->dst_address.as_u32[2];
1722 c0 ^= ip0->dst_address.as_u32[3];
1723
1724 hash_v3_finalize32 (a0, b0, c0);
1725
1726 c0 &= BITS (hash_bitmap) - 1;
1727 c0 = c0 / BITS (uword);
1728 m0 = (uword) 1 << (c0 % BITS (uword));
1729
1730 bm0 = hash_bitmap[c0];
1731 drop0 = (bm0 & m0) != 0;
1732
1733 /* Mark it as seen. */
1734 hash_bitmap[c0] = bm0 | m0;
1735
1736 from += 1;
1737 n_left_from -= 1;
1738 to_next_drop[0] = pi0;
1739 to_next_drop += 1;
1740 n_left_to_next_drop -= 1;
1741
Dave Barachd7cb1b52016-12-09 09:52:16 -05001742 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001743
Dave Barachd7cb1b52016-12-09 09:52:16 -05001744 /* If the interface is link-down, drop the pkt */
1745 if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1746 drop0 = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001747
Dave Barach75fc8542016-10-11 16:16:02 -04001748 p0->error =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001749 node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1750 : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001751 if (drop0)
1752 continue;
1753
Neale Rannsb80c5362016-10-08 13:03:40 +01001754 /*
1755 * the adj has been updated to a rewrite but the node the DPO that got
1756 * us here hasn't - yet. no big deal. we'll drop while we wait.
1757 */
1758 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1759 continue;
1760
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 {
1762 u32 bi0 = 0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001763 icmp6_neighbor_solicitation_header_t *h0;
1764 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001765
Dave Barach75fc8542016-10-11 16:16:02 -04001766 h0 = vlib_packet_template_get_packet
Dave Barachd7cb1b52016-12-09 09:52:16 -05001767 (vm, &im->discover_neighbor_packet_template, &bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768
Dave Barach75fc8542016-10-11 16:16:02 -04001769 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001770 * Build ethernet header.
1771 * Choose source address based on destination lookup
1772 * adjacency.
1773 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001774 if (ip6_src_address_for_packet (lm,
1775 sw_if_index0,
1776 &h0->ip.src_address))
1777 {
1778 /* There is no address on the interface */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001779 p0->error =
1780 node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1781 vlib_buffer_free (vm, &bi0, 1);
Pierre Pfisterd076f192016-06-22 12:58:30 +01001782 continue;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001783 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001784
Dave Barach75fc8542016-10-11 16:16:02 -04001785 /*
Dave Barachd7cb1b52016-12-09 09:52:16 -05001786 * Destination address is a solicited node multicast address.
1787 * We need to fill in
1788 * the low 24 bits with low 24 bits of target's address.
1789 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001790 h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1791 h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1792 h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1793
1794 h0->neighbor.target_address = ip0->dst_address;
1795
Dave Barach75fc8542016-10-11 16:16:02 -04001796 clib_memcpy (h0->link_layer_option.ethernet_address,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001797 hw_if0->hw_address, vec_len (hw_if0->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001798
Dave Barachd7cb1b52016-12-09 09:52:16 -05001799 /* $$$$ appears we need this; why is the checksum non-zero? */
1800 h0->neighbor.icmp.checksum = 0;
Dave Barach75fc8542016-10-11 16:16:02 -04001801 h0->neighbor.icmp.checksum =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001802 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1803 &bogus_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001804
Dave Barachd7cb1b52016-12-09 09:52:16 -05001805 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806
1807 vlib_buffer_copy_trace_flag (vm, p0, bi0);
1808 b0 = vlib_get_buffer (vm, bi0);
Dave Barach75fc8542016-10-11 16:16:02 -04001809 vnet_buffer (b0)->sw_if_index[VLIB_TX]
Dave Barachd7cb1b52016-12-09 09:52:16 -05001810 = vnet_buffer (p0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001811
1812 /* Add rewrite/encap string. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001813 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001814 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1815
John Lod1f5d042016-04-12 18:20:39 -04001816 next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001817
1818 vlib_set_next_frame_buffer (vm, node, next0, bi0);
1819 }
1820 }
1821
Dave Barach75fc8542016-10-11 16:16:02 -04001822 vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001823 n_left_to_next_drop);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 }
1825
1826 return frame->n_vectors;
1827}
1828
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001829static uword
1830ip6_discover_neighbor (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001831 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001832{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001833 return (ip6_discover_neighbor_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001834}
1835
1836static uword
Dave Barachd7cb1b52016-12-09 09:52:16 -05001837ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001838{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839 return (ip6_discover_neighbor_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001840}
1841
Dave Barachd7cb1b52016-12-09 09:52:16 -05001842static char *ip6_discover_neighbor_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001843 [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001844 [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
Pierre Pfisterd076f192016-06-22 12:58:30 +01001845 [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1846 = "no source address for ND solicitation",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001847};
1848
Dave Barachd7cb1b52016-12-09 09:52:16 -05001849/* *INDENT-OFF* */
1850VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1851{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001852 .function = ip6_discover_neighbor,
1853 .name = "ip6-discover-neighbor",
1854 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07001855 .format_trace = format_ip6_forward_next_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001856 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1857 .error_strings = ip6_discover_neighbor_error_strings,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001859 .next_nodes =
1860 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
John Lod1f5d042016-04-12 18:20:39 -04001862 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001863 },
1864};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001865/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001866
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867/* *INDENT-OFF* */
1868VLIB_REGISTER_NODE (ip6_glean_node) =
1869{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001870 .function = ip6_glean,
1871 .name = "ip6-glean",
1872 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001873 .format_trace = format_ip6_forward_next_trace,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001874 .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1875 .error_strings = ip6_discover_neighbor_error_strings,
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001876 .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877 .next_nodes =
1878 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001879 [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1880 [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1881 },
1882};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001883/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001884
Ed Warnickecb9cada2015-12-08 15:45:58 -07001885clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1887{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001888 vnet_main_t *vnm = vnet_get_main ();
1889 ip6_main_t *im = &ip6_main;
1890 icmp6_neighbor_solicitation_header_t *h;
1891 ip6_address_t *src;
1892 ip_interface_address_t *ia;
1893 ip_adjacency_t *adj;
1894 vnet_hw_interface_t *hi;
1895 vnet_sw_interface_t *si;
1896 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001897 u32 bi = 0;
1898 int bogus_length;
1899
1900 si = vnet_get_sw_interface (vnm, sw_if_index);
1901
1902 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1903 {
1904 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001905 format_ip6_address, dst,
1906 format_vnet_sw_if_index_name, vnm,
1907 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001908 }
1909
Dave Barachd7cb1b52016-12-09 09:52:16 -05001910 src =
1911 ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1912 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001913 {
1914 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04001915 return clib_error_return
Dave Barachd7cb1b52016-12-09 09:52:16 -05001916 (0, "no matching interface address for destination %U (interface %U)",
1917 format_ip6_address, dst,
1918 format_vnet_sw_if_index_name, vnm, sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001919 }
1920
Dave Barachd7cb1b52016-12-09 09:52:16 -05001921 h =
1922 vlib_packet_template_get_packet (vm,
1923 &im->discover_neighbor_packet_template,
1924 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001925
1926 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1927
1928 /* Destination address is a solicited node multicast address. We need to fill in
1929 the low 24 bits with low 24 bits of target's address. */
1930 h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1931 h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1932 h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1933
1934 h->ip.src_address = src[0];
1935 h->neighbor.target_address = dst[0];
1936
Dave Barachd7cb1b52016-12-09 09:52:16 -05001937 clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1938 vec_len (hi->hw_address));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001939
Dave Barach75fc8542016-10-11 16:16:02 -04001940 h->neighbor.icmp.checksum =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001941 ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001942 ASSERT (bogus_length == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001943
1944 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001945 vnet_buffer (b)->sw_if_index[VLIB_RX] =
1946 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001947
1948 /* Add encapsulation string for software interface (e.g. ethernet header). */
1949 adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
1950 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1951 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1952
1953 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001954 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1955 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001956 to_next[0] = bi;
1957 f->n_vectors = 1;
1958 vlib_put_frame_to_node (vm, hi->output_node_index, f);
1959 }
1960
1961 return /* no error */ 0;
1962}
1963
Dave Barachd7cb1b52016-12-09 09:52:16 -05001964typedef enum
1965{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001966 IP6_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001967 IP6_REWRITE_NEXT_ICMP_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968} ip6_rewrite_next_t;
1969
1970always_inline uword
1971ip6_rewrite_inline (vlib_main_t * vm,
1972 vlib_node_runtime_t * node,
Neale Ranns32e1c012016-11-22 17:07:28 +00001973 vlib_frame_t * frame, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001974{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001975 ip_lookup_main_t *lm = &ip6_main.lookup_main;
1976 u32 *from = vlib_frame_vector_args (frame);
1977 u32 n_left_from, n_left_to_next, *to_next, next_index;
1978 vlib_node_runtime_t *error_node =
1979 vlib_node_get_runtime (vm, ip6_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001980
1981 n_left_from = frame->n_vectors;
1982 next_index = node->cached_next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001983 u32 cpu_index = os_get_cpu_number ();
Dave Barach75fc8542016-10-11 16:16:02 -04001984
Ed Warnickecb9cada2015-12-08 15:45:58 -07001985 while (n_left_from > 0)
1986 {
1987 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1988
1989 while (n_left_from >= 4 && n_left_to_next >= 2)
1990 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001991 ip_adjacency_t *adj0, *adj1;
1992 vlib_buffer_t *p0, *p1;
1993 ip6_header_t *ip0, *ip1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994 u32 pi0, rw_len0, next0, error0, adj_index0;
1995 u32 pi1, rw_len1, next1, error1, adj_index1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001996 u32 tx_sw_if_index0, tx_sw_if_index1;
Dave Barach75fc8542016-10-11 16:16:02 -04001997
Ed Warnickecb9cada2015-12-08 15:45:58 -07001998 /* Prefetch next iteration. */
1999 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002000 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002001
2002 p2 = vlib_get_buffer (vm, from[2]);
2003 p3 = vlib_get_buffer (vm, from[3]);
2004
2005 vlib_prefetch_buffer_header (p2, LOAD);
2006 vlib_prefetch_buffer_header (p3, LOAD);
2007
2008 CLIB_PREFETCH (p2->pre_data, 32, STORE);
2009 CLIB_PREFETCH (p3->pre_data, 32, STORE);
2010
2011 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2012 CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2013 }
2014
2015 pi0 = to_next[0] = from[0];
2016 pi1 = to_next[1] = from[1];
2017
2018 from += 2;
2019 n_left_from -= 2;
2020 to_next += 2;
2021 n_left_to_next -= 2;
Dave Barach75fc8542016-10-11 16:16:02 -04002022
Ed Warnickecb9cada2015-12-08 15:45:58 -07002023 p0 = vlib_get_buffer (vm, pi0);
2024 p1 = vlib_get_buffer (vm, pi1);
2025
Neale Rannsf06aea52016-11-29 06:51:37 -08002026 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2027 adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002028
Dave Barachd7cb1b52016-12-09 09:52:16 -05002029 /* We should never rewrite a pkt using the MISS adjacency */
2030 ASSERT (adj_index0 && adj_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031
2032 ip0 = vlib_buffer_get_current (p0);
2033 ip1 = vlib_buffer_get_current (p1);
2034
2035 error0 = error1 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002036 next0 = next1 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002037
Dave Barachd7cb1b52016-12-09 09:52:16 -05002038 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002039 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002040 i32 hop_limit0 = ip0->hop_limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002041
2042 /* Input node should have reject packets with hop limit 0. */
2043 ASSERT (ip0->hop_limit > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044
2045 hop_limit0 -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002046
2047 ip0->hop_limit = hop_limit0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002048
Dave Barachd7cb1b52016-12-09 09:52:16 -05002049 /*
2050 * If the hop count drops below 1 when forwarding, generate
2051 * an ICMP response.
2052 */
2053 if (PREDICT_FALSE (hop_limit0 <= 0))
2054 {
2055 error0 = IP6_ERROR_TIME_EXPIRED;
2056 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2057 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2058 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2059 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2060 0);
2061 }
Neale Rannsf06aea52016-11-29 06:51:37 -08002062 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002063 else
2064 {
2065 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2066 }
2067 if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2068 {
Neale Rannsf06aea52016-11-29 06:51:37 -08002069 i32 hop_limit1 = ip1->hop_limit;
2070
2071 /* Input node should have reject packets with hop limit 0. */
2072 ASSERT (ip1->hop_limit > 0);
2073
2074 hop_limit1 -= 1;
2075
2076 ip1->hop_limit = hop_limit1;
2077
Dave Barachd7cb1b52016-12-09 09:52:16 -05002078 /*
2079 * If the hop count drops below 1 when forwarding, generate
2080 * an ICMP response.
2081 */
2082 if (PREDICT_FALSE (hop_limit1 <= 0))
2083 {
2084 error1 = IP6_ERROR_TIME_EXPIRED;
2085 next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2086 vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2087 icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2088 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2089 0);
2090 }
2091 }
2092 else
2093 {
2094 p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2095 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002096 adj0 = ip_get_adjacency (lm, adj_index0);
2097 adj1 = ip_get_adjacency (lm, adj_index1);
2098
Ed Warnickecb9cada2015-12-08 15:45:58 -07002099 rw_len0 = adj0[0].rewrite_header.data_bytes;
2100 rw_len1 = adj1[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002101 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2102 vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103
Neale Ranns044183f2017-01-24 01:34:25 -08002104 vlib_increment_combined_counter
2105 (&adjacency_counters,
2106 cpu_index,
2107 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2108 vlib_increment_combined_counter
2109 (&adjacency_counters,
2110 cpu_index, adj_index1,
2111 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002112
2113 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002114 error0 =
2115 (vlib_buffer_length_in_chain (vm, p0) >
2116 adj0[0].
2117 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2118 error0);
2119 error1 =
2120 (vlib_buffer_length_in_chain (vm, p1) >
2121 adj1[0].
2122 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2123 error1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002124
Dave Barachd7cb1b52016-12-09 09:52:16 -05002125 /* Don't adjust the buffer for hop count issue; icmp-error node
2126 * wants to see the IP headerr */
2127 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2128 {
2129 p0->current_data -= rw_len0;
2130 p0->current_length += rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002131
Dave Barachd7cb1b52016-12-09 09:52:16 -05002132 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2133 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2134 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002135
Dave Barachd7cb1b52016-12-09 09:52:16 -05002136 vnet_feature_arc_start (lm->output_feature_arc_index,
2137 tx_sw_if_index0, &next0, p0);
2138 }
2139 if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2140 {
2141 p1->current_data -= rw_len1;
2142 p1->current_length += rw_len1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002143
Dave Barachd7cb1b52016-12-09 09:52:16 -05002144 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2145 vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2146 next1 = adj1[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002147
Dave Barachd7cb1b52016-12-09 09:52:16 -05002148 vnet_feature_arc_start (lm->output_feature_arc_index,
2149 tx_sw_if_index1, &next1, p1);
2150 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002151
2152 /* Guess we are only writing on simple Ethernet header. */
2153 vnet_rewrite_two_headers (adj0[0], adj1[0],
Dave Barachd7cb1b52016-12-09 09:52:16 -05002154 ip0, ip1, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002155
Neale Ranns5e575b12016-10-03 09:40:25 +01002156 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002157 {
2158 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2159 adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2160 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002161 if (is_mcast)
2162 {
2163 /*
2164 * copy bytes from the IP address into the MAC rewrite
2165 */
2166 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0);
2167 vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1, 0);
2168 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002169
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2171 to_next, n_left_to_next,
2172 pi0, pi1, next0, next1);
2173 }
2174
2175 while (n_left_from > 0 && n_left_to_next > 0)
2176 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002177 ip_adjacency_t *adj0;
2178 vlib_buffer_t *p0;
2179 ip6_header_t *ip0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002180 u32 pi0, rw_len0;
2181 u32 adj_index0, next0, error0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002182 u32 tx_sw_if_index0;
Dave Barach75fc8542016-10-11 16:16:02 -04002183
Ed Warnickecb9cada2015-12-08 15:45:58 -07002184 pi0 = to_next[0] = from[0];
2185
2186 p0 = vlib_get_buffer (vm, pi0);
2187
Neale Rannsf06aea52016-11-29 06:51:37 -08002188 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002189
Dave Barachd7cb1b52016-12-09 09:52:16 -05002190 /* We should never rewrite a pkt using the MISS adjacency */
2191 ASSERT (adj_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002192
2193 adj0 = ip_get_adjacency (lm, adj_index0);
Dave Barach75fc8542016-10-11 16:16:02 -04002194
Ed Warnickecb9cada2015-12-08 15:45:58 -07002195 ip0 = vlib_buffer_get_current (p0);
2196
2197 error0 = IP6_ERROR_NONE;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002198 next0 = IP6_REWRITE_NEXT_DROP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002199
2200 /* Check hop limit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002201 if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202 {
2203 i32 hop_limit0 = ip0->hop_limit;
2204
2205 ASSERT (ip0->hop_limit > 0);
2206
2207 hop_limit0 -= 1;
2208
2209 ip0->hop_limit = hop_limit0;
2210
Dave Barachd7cb1b52016-12-09 09:52:16 -05002211 if (PREDICT_FALSE (hop_limit0 <= 0))
2212 {
2213 /*
2214 * If the hop count drops below 1 when forwarding, generate
2215 * an ICMP response.
2216 */
2217 error0 = IP6_ERROR_TIME_EXPIRED;
2218 next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2219 vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2220 icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2221 ICMP6_time_exceeded_ttl_exceeded_in_transit,
2222 0);
2223 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002224 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002225 else
2226 {
2227 p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2228 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002229
Ed Warnickecb9cada2015-12-08 15:45:58 -07002230 /* Guess we are only writing on simple Ethernet header. */
2231 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
Dave Barach75fc8542016-10-11 16:16:02 -04002232
Ed Warnickecb9cada2015-12-08 15:45:58 -07002233 /* Update packet buffer attributes/set output interface. */
2234 rw_len0 = adj0[0].rewrite_header.data_bytes;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002235 vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236
Neale Ranns044183f2017-01-24 01:34:25 -08002237 vlib_increment_combined_counter
2238 (&adjacency_counters,
2239 cpu_index,
2240 adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002241
2242 /* Check MTU of outgoing interface. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002243 error0 =
2244 (vlib_buffer_length_in_chain (vm, p0) >
2245 adj0[0].
2246 rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2247 error0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248
Dave Barachd7cb1b52016-12-09 09:52:16 -05002249 /* Don't adjust the buffer for hop count issue; icmp-error node
2250 * wants to see the IP headerr */
2251 if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2252 {
Chris Luke816f3e12016-06-14 16:24:47 -04002253 p0->current_data -= rw_len0;
2254 p0->current_length += rw_len0;
2255
Dave Barachd7cb1b52016-12-09 09:52:16 -05002256 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
Dave Barach5331c722016-08-17 11:54:30 -04002257
Dave Barachd7cb1b52016-12-09 09:52:16 -05002258 vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2259 next0 = adj0[0].rewrite_header.next_index;
Dave Barach5331c722016-08-17 11:54:30 -04002260
Dave Barachd7cb1b52016-12-09 09:52:16 -05002261 vnet_feature_arc_start (lm->output_feature_arc_index,
2262 tx_sw_if_index0, &next0, p0);
2263 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002264
Neale Ranns5e575b12016-10-03 09:40:25 +01002265 if (is_midchain)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002266 {
2267 adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2268 }
Neale Ranns32e1c012016-11-22 17:07:28 +00002269 if (is_mcast)
2270 {
2271 vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0, 0);
2272 }
Neale Ranns5e575b12016-10-03 09:40:25 +01002273
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274 p0->error = error_node->errors[error0];
2275
2276 from += 1;
2277 n_left_from -= 1;
2278 to_next += 1;
2279 n_left_to_next -= 1;
Dave Barach75fc8542016-10-11 16:16:02 -04002280
Ed Warnickecb9cada2015-12-08 15:45:58 -07002281 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2282 to_next, n_left_to_next,
2283 pi0, next0);
2284 }
2285
2286 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2287 }
2288
2289 /* Need to do trace after rewrites to pick up new packet data. */
2290 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002291 ip6_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292
2293 return frame->n_vectors;
2294}
2295
2296static uword
Neale Rannsf06aea52016-11-29 06:51:37 -08002297ip6_rewrite (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002298 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299{
Neale Ranns32e1c012016-11-22 17:07:28 +00002300 return ip6_rewrite_inline (vm, node, frame, 0, 0);
2301}
2302
2303static uword
2304ip6_rewrite_mcast (vlib_main_t * vm,
2305 vlib_node_runtime_t * node, vlib_frame_t * frame)
2306{
2307 return ip6_rewrite_inline (vm, node, frame, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002308}
2309
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002310static uword
2311ip6_midchain (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002312 vlib_node_runtime_t * node, vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002313{
Neale Ranns32e1c012016-11-22 17:07:28 +00002314 return ip6_rewrite_inline (vm, node, frame, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002315}
2316
Dave Barachd7cb1b52016-12-09 09:52:16 -05002317/* *INDENT-OFF* */
2318VLIB_REGISTER_NODE (ip6_midchain_node) =
2319{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002320 .function = ip6_midchain,
2321 .name = "ip6-midchain",
2322 .vector_size = sizeof (u32),
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002323 .format_trace = format_ip6_forward_next_trace,
Neale Ranns5e575b12016-10-03 09:40:25 +01002324 .sibling_of = "ip6-rewrite",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002325 };
2326/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002327
Dave Barachd7cb1b52016-12-09 09:52:16 -05002328VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002329
Dave Barachd7cb1b52016-12-09 09:52:16 -05002330/* *INDENT-OFF* */
2331VLIB_REGISTER_NODE (ip6_rewrite_node) =
2332{
Neale Rannsf06aea52016-11-29 06:51:37 -08002333 .function = ip6_rewrite,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002334 .name = "ip6-rewrite",
2335 .vector_size = sizeof (u32),
Pierre Pfistera38c3df2016-06-13 10:28:09 +01002336 .format_trace = format_ip6_rewrite_trace,
Chris Luke816f3e12016-06-14 16:24:47 -04002337 .n_next_nodes = 2,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002338 .next_nodes =
2339 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002340 [IP6_REWRITE_NEXT_DROP] = "error-drop",
Chris Luke816f3e12016-06-14 16:24:47 -04002341 [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002342 },
2343};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002344/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002345
Neale Rannsf06aea52016-11-29 06:51:37 -08002346VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
Damjan Marion1c80e832016-05-11 23:07:18 +02002347
Neale Ranns32e1c012016-11-22 17:07:28 +00002348/* *INDENT-OFF* */
2349VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
2350{
2351 .function = ip6_rewrite_mcast,
2352 .name = "ip6-rewrite-mcast",
2353 .vector_size = sizeof (u32),
2354 .format_trace = format_ip6_rewrite_trace,
2355 .sibling_of = "ip6-rewrite",
2356};
2357/* *INDENT-ON* */
2358
2359VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
2360
Ole Troan944f5482016-05-24 11:56:58 +02002361/*
2362 * Hop-by-Hop handling
2363 */
Ole Troan944f5482016-05-24 11:56:58 +02002364ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2365
2366#define foreach_ip6_hop_by_hop_error \
2367_(PROCESSED, "pkts with ip6 hop-by-hop options") \
2368_(FORMAT, "incorrectly formatted hop-by-hop options") \
2369_(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2370
Neale Ranns32e1c012016-11-22 17:07:28 +00002371/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002372typedef enum
2373{
Ole Troan944f5482016-05-24 11:56:58 +02002374#define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2375 foreach_ip6_hop_by_hop_error
2376#undef _
Neale Ranns32e1c012016-11-22 17:07:28 +00002377 IP6_HOP_BY_HOP_N_ERROR,
Ole Troan944f5482016-05-24 11:56:58 +02002378} ip6_hop_by_hop_error_t;
Neale Ranns32e1c012016-11-22 17:07:28 +00002379/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002380
2381/*
2382 * Primary h-b-h handler trace support
2383 * We work pretty hard on the problem for obvious reasons
2384 */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002385typedef struct
2386{
Ole Troan944f5482016-05-24 11:56:58 +02002387 u32 next_index;
2388 u32 trace_len;
2389 u8 option_data[256];
2390} ip6_hop_by_hop_trace_t;
2391
2392vlib_node_registration_t ip6_hop_by_hop_node;
2393
Dave Barachd7cb1b52016-12-09 09:52:16 -05002394static char *ip6_hop_by_hop_error_strings[] = {
Ole Troan944f5482016-05-24 11:56:58 +02002395#define _(sym,string) string,
2396 foreach_ip6_hop_by_hop_error
2397#undef _
2398};
2399
2400static u8 *
2401format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2402{
2403 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2404 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002405 ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
Ole Troan944f5482016-05-24 11:56:58 +02002406 ip6_hop_by_hop_header_t *hbh0;
2407 ip6_hop_by_hop_option_t *opt0, *limit0;
2408 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2409
2410 u8 type0;
2411
Dave Barachd7cb1b52016-12-09 09:52:16 -05002412 hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
Ole Troan944f5482016-05-24 11:56:58 +02002413
2414 s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002415 t->next_index, (hbh0->length + 1) << 3, t->trace_len);
Ole Troan944f5482016-05-24 11:56:58 +02002416
Dave Barachd7cb1b52016-12-09 09:52:16 -05002417 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2418 limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
Ole Troan944f5482016-05-24 11:56:58 +02002419
Dave Barachd7cb1b52016-12-09 09:52:16 -05002420 while (opt0 < limit0)
2421 {
2422 type0 = opt0->type;
2423 switch (type0)
2424 {
2425 case 0: /* Pad, just stop */
2426 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2427 break;
Ole Troan944f5482016-05-24 11:56:58 +02002428
Dave Barachd7cb1b52016-12-09 09:52:16 -05002429 default:
2430 if (hm->trace[type0])
2431 {
2432 s = (*hm->trace[type0]) (s, opt0);
2433 }
2434 else
2435 {
2436 s =
2437 format (s, "\n unrecognized option %d length %d", type0,
2438 opt0->length);
2439 }
2440 opt0 =
2441 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2442 sizeof (ip6_hop_by_hop_option_t));
2443 break;
2444 }
Ole Troan944f5482016-05-24 11:56:58 +02002445 }
Ole Troan944f5482016-05-24 11:56:58 +02002446 return s;
2447}
2448
Dave Barachd7cb1b52016-12-09 09:52:16 -05002449always_inline u8
2450ip6_scan_hbh_options (vlib_buffer_t * b0,
2451 ip6_header_t * ip0,
2452 ip6_hop_by_hop_header_t * hbh0,
2453 ip6_hop_by_hop_option_t * opt0,
2454 ip6_hop_by_hop_option_t * limit0, u32 * next0)
Shwethaa91cbe62016-08-08 15:51:04 +01002455{
2456 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2457 u8 type0;
2458 u8 error0 = 0;
2459
2460 while (opt0 < limit0)
2461 {
2462 type0 = opt0->type;
2463 switch (type0)
2464 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002465 case 0: /* Pad1 */
2466 opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
Shwethaa91cbe62016-08-08 15:51:04 +01002467 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002468 case 1: /* PadN */
Shwethaa91cbe62016-08-08 15:51:04 +01002469 break;
2470 default:
2471 if (hm->options[type0])
2472 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002473 if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2474 {
Shwethaa91cbe62016-08-08 15:51:04 +01002475 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002476 return (error0);
2477 }
Shwethaa91cbe62016-08-08 15:51:04 +01002478 }
2479 else
2480 {
2481 /* Unrecognized mandatory option, check the two high order bits */
2482 switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2483 {
2484 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2485 break;
2486 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2487 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2488 *next0 = IP_LOOKUP_NEXT_DROP;
2489 break;
2490 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2491 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2492 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002493 icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2494 ICMP6_parameter_problem_unrecognized_option,
2495 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002496 break;
2497 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2498 error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002499 if (!ip6_address_is_multicast (&ip0->dst_address))
Shwethaa91cbe62016-08-08 15:51:04 +01002500 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002501 *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2502 icmp6_error_set_vnet_buffer (b0,
2503 ICMP6_parameter_problem,
2504 ICMP6_parameter_problem_unrecognized_option,
2505 (u8 *) opt0 - (u8 *) ip0);
Shwethaa91cbe62016-08-08 15:51:04 +01002506 }
2507 else
2508 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002509 *next0 = IP_LOOKUP_NEXT_DROP;
Shwethaa91cbe62016-08-08 15:51:04 +01002510 }
2511 break;
2512 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002513 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002514 }
2515 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002516 opt0 =
2517 (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2518 sizeof (ip6_hop_by_hop_option_t));
Shwethaa91cbe62016-08-08 15:51:04 +01002519 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002520 return (error0);
Shwethaa91cbe62016-08-08 15:51:04 +01002521}
2522
Ole Troan944f5482016-05-24 11:56:58 +02002523/*
2524 * Process the Hop-by-Hop Options header
2525 */
2526static uword
2527ip6_hop_by_hop (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002528 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ole Troan944f5482016-05-24 11:56:58 +02002529{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002530 vlib_node_runtime_t *error_node =
2531 vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
Ole Troan944f5482016-05-24 11:56:58 +02002532 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2533 u32 n_left_from, *from, *to_next;
2534 ip_lookup_next_t next_index;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002535 ip6_main_t *im = &ip6_main;
Ole Troan944f5482016-05-24 11:56:58 +02002536 ip_lookup_main_t *lm = &im->lookup_main;
2537
2538 from = vlib_frame_vector_args (frame);
2539 n_left_from = frame->n_vectors;
2540 next_index = node->cached_next_index;
2541
Dave Barachd7cb1b52016-12-09 09:52:16 -05002542 while (n_left_from > 0)
2543 {
2544 u32 n_left_to_next;
Ole Troan944f5482016-05-24 11:56:58 +02002545
Dave Barachd7cb1b52016-12-09 09:52:16 -05002546 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ole Troan944f5482016-05-24 11:56:58 +02002547
Dave Barachd7cb1b52016-12-09 09:52:16 -05002548 while (n_left_from >= 4 && n_left_to_next >= 2)
Shwethaa91cbe62016-08-08 15:51:04 +01002549 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002550 u32 bi0, bi1;
2551 vlib_buffer_t *b0, *b1;
2552 u32 next0, next1;
2553 ip6_header_t *ip0, *ip1;
2554 ip6_hop_by_hop_header_t *hbh0, *hbh1;
2555 ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2556 u8 error0 = 0, error1 = 0;
2557
2558 /* Prefetch next iteration. */
2559 {
2560 vlib_buffer_t *p2, *p3;
2561
2562 p2 = vlib_get_buffer (vm, from[2]);
2563 p3 = vlib_get_buffer (vm, from[3]);
2564
2565 vlib_prefetch_buffer_header (p2, LOAD);
2566 vlib_prefetch_buffer_header (p3, LOAD);
2567
2568 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2569 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Shwethaa91cbe62016-08-08 15:51:04 +01002570 }
2571
Dave Barachd7cb1b52016-12-09 09:52:16 -05002572 /* Speculatively enqueue b0, b1 to the current next frame */
2573 to_next[0] = bi0 = from[0];
2574 to_next[1] = bi1 = from[1];
2575 from += 2;
2576 to_next += 2;
2577 n_left_from -= 2;
2578 n_left_to_next -= 2;
2579
2580 b0 = vlib_get_buffer (vm, bi0);
2581 b1 = vlib_get_buffer (vm, bi1);
2582
2583 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2584 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2585 ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2586 u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2587 ip_adjacency_t *adj1 = ip_get_adjacency (lm, adj_index1);
2588
2589 /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2590 next0 = adj0->lookup_next_index;
2591 next1 = adj1->lookup_next_index;
2592
2593 ip0 = vlib_buffer_get_current (b0);
2594 ip1 = vlib_buffer_get_current (b1);
2595 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2596 hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2597 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2598 opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2599 limit0 =
2600 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2601 ((hbh0->length + 1) << 3));
2602 limit1 =
2603 (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2604 ((hbh1->length + 1) << 3));
2605
2606 /*
2607 * Basic validity checks
2608 */
2609 if ((hbh0->length + 1) << 3 >
2610 clib_net_to_host_u16 (ip0->payload_length))
2611 {
2612 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2613 next0 = IP_LOOKUP_NEXT_DROP;
2614 goto outdual;
2615 }
2616 /* Scan the set of h-b-h options, process ones that we understand */
2617 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2618
2619 if ((hbh1->length + 1) << 3 >
2620 clib_net_to_host_u16 (ip1->payload_length))
2621 {
2622 error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2623 next1 = IP_LOOKUP_NEXT_DROP;
2624 goto outdual;
2625 }
2626 /* Scan the set of h-b-h options, process ones that we understand */
2627 error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2628
2629 outdual:
2630 /* Has the classifier flagged this buffer for special treatment? */
2631 if (PREDICT_FALSE
2632 ((error0 == 0)
2633 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2634 next0 = hm->next_override;
2635
2636 /* Has the classifier flagged this buffer for special treatment? */
2637 if (PREDICT_FALSE
2638 ((error1 == 0)
2639 && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2640 next1 = hm->next_override;
2641
2642 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2643 {
2644 if (b0->flags & VLIB_BUFFER_IS_TRACED)
2645 {
2646 ip6_hop_by_hop_trace_t *t =
2647 vlib_add_trace (vm, node, b0, sizeof (*t));
2648 u32 trace_len = (hbh0->length + 1) << 3;
2649 t->next_index = next0;
2650 /* Capture the h-b-h option verbatim */
2651 trace_len =
2652 trace_len <
2653 ARRAY_LEN (t->option_data) ? trace_len :
2654 ARRAY_LEN (t->option_data);
2655 t->trace_len = trace_len;
2656 clib_memcpy (t->option_data, hbh0, trace_len);
2657 }
2658 if (b1->flags & VLIB_BUFFER_IS_TRACED)
2659 {
2660 ip6_hop_by_hop_trace_t *t =
2661 vlib_add_trace (vm, node, b1, sizeof (*t));
2662 u32 trace_len = (hbh1->length + 1) << 3;
2663 t->next_index = next1;
2664 /* Capture the h-b-h option verbatim */
2665 trace_len =
2666 trace_len <
2667 ARRAY_LEN (t->option_data) ? trace_len :
2668 ARRAY_LEN (t->option_data);
2669 t->trace_len = trace_len;
2670 clib_memcpy (t->option_data, hbh1, trace_len);
2671 }
2672
2673 }
2674
2675 b0->error = error_node->errors[error0];
2676 b1->error = error_node->errors[error1];
2677
2678 /* verify speculative enqueue, maybe switch current next frame */
2679 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2680 n_left_to_next, bi0, bi1, next0,
2681 next1);
Shwethaa91cbe62016-08-08 15:51:04 +01002682 }
2683
Dave Barachd7cb1b52016-12-09 09:52:16 -05002684 while (n_left_from > 0 && n_left_to_next > 0)
2685 {
2686 u32 bi0;
2687 vlib_buffer_t *b0;
2688 u32 next0;
2689 ip6_header_t *ip0;
2690 ip6_hop_by_hop_header_t *hbh0;
2691 ip6_hop_by_hop_option_t *opt0, *limit0;
2692 u8 error0 = 0;
Shwethaa91cbe62016-08-08 15:51:04 +01002693
Dave Barachd7cb1b52016-12-09 09:52:16 -05002694 /* Speculatively enqueue b0 to the current next frame */
2695 bi0 = from[0];
2696 to_next[0] = bi0;
2697 from += 1;
2698 to_next += 1;
2699 n_left_from -= 1;
2700 n_left_to_next -= 1;
2701
2702 b0 = vlib_get_buffer (vm, bi0);
2703 /*
2704 * Default use the next_index from the adjacency.
2705 * A HBH option rarely redirects to a different node
2706 */
2707 u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2708 ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2709 next0 = adj0->lookup_next_index;
2710
2711 ip0 = vlib_buffer_get_current (b0);
2712 hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2713 opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2714 limit0 =
2715 (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2716 ((hbh0->length + 1) << 3));
2717
2718 /*
2719 * Basic validity checks
2720 */
2721 if ((hbh0->length + 1) << 3 >
2722 clib_net_to_host_u16 (ip0->payload_length))
2723 {
2724 error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2725 next0 = IP_LOOKUP_NEXT_DROP;
2726 goto out0;
2727 }
2728
2729 /* Scan the set of h-b-h options, process ones that we understand */
2730 error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2731
2732 out0:
2733 /* Has the classifier flagged this buffer for special treatment? */
2734 if (PREDICT_FALSE
2735 ((error0 == 0)
2736 && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2737 next0 = hm->next_override;
2738
2739 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2740 {
2741 ip6_hop_by_hop_trace_t *t =
2742 vlib_add_trace (vm, node, b0, sizeof (*t));
2743 u32 trace_len = (hbh0->length + 1) << 3;
2744 t->next_index = next0;
2745 /* Capture the h-b-h option verbatim */
2746 trace_len =
2747 trace_len <
2748 ARRAY_LEN (t->option_data) ? trace_len :
2749 ARRAY_LEN (t->option_data);
2750 t->trace_len = trace_len;
2751 clib_memcpy (t->option_data, hbh0, trace_len);
2752 }
2753
2754 b0->error = error_node->errors[error0];
2755
2756 /* verify speculative enqueue, maybe switch current next frame */
2757 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2758 n_left_to_next, bi0, next0);
2759 }
2760 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Shwethaa91cbe62016-08-08 15:51:04 +01002761 }
Ole Troan944f5482016-05-24 11:56:58 +02002762 return frame->n_vectors;
2763}
2764
Dave Barachd7cb1b52016-12-09 09:52:16 -05002765/* *INDENT-OFF* */
2766VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2767{
Ole Troan944f5482016-05-24 11:56:58 +02002768 .function = ip6_hop_by_hop,
2769 .name = "ip6-hop-by-hop",
Ole Troan964f93e2016-06-10 13:22:36 +02002770 .sibling_of = "ip6-lookup",
Ole Troan944f5482016-05-24 11:56:58 +02002771 .vector_size = sizeof (u32),
2772 .format_trace = format_ip6_hop_by_hop_trace,
2773 .type = VLIB_NODE_TYPE_INTERNAL,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002774 .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
Ole Troan944f5482016-05-24 11:56:58 +02002775 .error_strings = ip6_hop_by_hop_error_strings,
Ole Troan964f93e2016-06-10 13:22:36 +02002776 .n_next_nodes = 0,
Ole Troan944f5482016-05-24 11:56:58 +02002777};
Dave Barachd7cb1b52016-12-09 09:52:16 -05002778/* *INDENT-ON* */
Ole Troan944f5482016-05-24 11:56:58 +02002779
Dave Barach5331c722016-08-17 11:54:30 -04002780VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
Ole Troan944f5482016-05-24 11:56:58 +02002781
2782static clib_error_t *
2783ip6_hop_by_hop_init (vlib_main_t * vm)
2784{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002785 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2786 memset (hm->options, 0, sizeof (hm->options));
2787 memset (hm->trace, 0, sizeof (hm->trace));
Shwethaa91cbe62016-08-08 15:51:04 +01002788 hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
Ole Troan944f5482016-05-24 11:56:58 +02002789 return (0);
2790}
2791
2792VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2793
Dave Barachd7cb1b52016-12-09 09:52:16 -05002794void
2795ip6_hbh_set_next_override (uword next)
Shwethaa91cbe62016-08-08 15:51:04 +01002796{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002797 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Shwethaa91cbe62016-08-08 15:51:04 +01002798
2799 hm->next_override = next;
2800}
2801
Ole Troan944f5482016-05-24 11:56:58 +02002802int
2803ip6_hbh_register_option (u8 option,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002804 int options (vlib_buffer_t * b, ip6_header_t * ip,
2805 ip6_hop_by_hop_option_t * opt),
2806 u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
Ole Troan944f5482016-05-24 11:56:58 +02002807{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002808 ip6_main_t *im = &ip6_main;
2809 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002810
2811 ASSERT (option < ARRAY_LEN (hm->options));
2812
2813 /* Already registered */
2814 if (hm->options[option])
2815 return (-1);
2816
2817 hm->options[option] = options;
2818 hm->trace[option] = trace;
2819
2820 /* Set global variable */
2821 im->hbh_enabled = 1;
2822
2823 return (0);
2824}
2825
2826int
2827ip6_hbh_unregister_option (u8 option)
2828{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002829 ip6_main_t *im = &ip6_main;
2830 ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
Ole Troan944f5482016-05-24 11:56:58 +02002831
2832 ASSERT (option < ARRAY_LEN (hm->options));
2833
2834 /* Not registered */
2835 if (!hm->options[option])
2836 return (-1);
2837
2838 hm->options[option] = NULL;
2839 hm->trace[option] = NULL;
2840
2841 /* Disable global knob if this was the last option configured */
2842 int i;
2843 bool found = false;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002844 for (i = 0; i < 256; i++)
2845 {
2846 if (hm->options[option])
2847 {
2848 found = true;
2849 break;
2850 }
Ole Troan944f5482016-05-24 11:56:58 +02002851 }
Ole Troan944f5482016-05-24 11:56:58 +02002852 if (!found)
2853 im->hbh_enabled = 0;
2854
2855 return (0);
2856}
2857
Ed Warnickecb9cada2015-12-08 15:45:58 -07002858/* Global IP6 main. */
2859ip6_main_t ip6_main;
2860
2861static clib_error_t *
2862ip6_lookup_init (vlib_main_t * vm)
2863{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002864 ip6_main_t *im = &ip6_main;
2865 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866 uword i;
2867
Damjan Marion8b3191e2016-11-09 19:54:20 +01002868 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2869 return error;
2870
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2872 {
2873 u32 j, i0, i1;
2874
2875 i0 = i / 32;
2876 i1 = i % 32;
2877
2878 for (j = 0; j < i0; j++)
2879 im->fib_masks[i].as_u32[j] = ~0;
2880
2881 if (i1)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002882 im->fib_masks[i].as_u32[i0] =
2883 clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002884 }
2885
2886 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2887
2888 if (im->lookup_table_nbuckets == 0)
2889 im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2890
Dave Barachd7cb1b52016-12-09 09:52:16 -05002891 im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002892
2893 if (im->lookup_table_size == 0)
2894 im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
Dave Barach75fc8542016-10-11 16:16:02 -04002895
Dave Barachd7cb1b52016-12-09 09:52:16 -05002896 BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2897 "ip6 FIB fwding table",
2898 im->lookup_table_nbuckets, im->lookup_table_size);
2899 BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2900 "ip6 FIB non-fwding table",
2901 im->lookup_table_nbuckets, im->lookup_table_size);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002902
Ed Warnickecb9cada2015-12-08 15:45:58 -07002903 /* Create FIB with index 0 and table id of 0. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002904 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Neale Ranns32e1c012016-11-22 17:07:28 +00002905 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906
2907 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002908 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002909 pn = pg_get_node (ip6_lookup_node.index);
2910 pn->unformat_edit = unformat_pg_ip6_header;
2911 }
2912
Ole Troan944f5482016-05-24 11:56:58 +02002913 /* Unless explicitly configured, don't process HBH options */
2914 im->hbh_enabled = 0;
2915
Ed Warnickecb9cada2015-12-08 15:45:58 -07002916 {
2917 icmp6_neighbor_solicitation_header_t p;
2918
2919 memset (&p, 0, sizeof (p));
2920
Dave Barachd7cb1b52016-12-09 09:52:16 -05002921 p.ip.ip_version_traffic_class_and_flow_label =
2922 clib_host_to_net_u32 (0x6 << 28);
2923 p.ip.payload_length =
2924 clib_host_to_net_u16 (sizeof (p) -
2925 STRUCT_OFFSET_OF
2926 (icmp6_neighbor_solicitation_header_t, neighbor));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002927 p.ip.protocol = IP_PROTOCOL_ICMP6;
2928 p.ip.hop_limit = 255;
2929 ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2930
2931 p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2932
Dave Barachd7cb1b52016-12-09 09:52:16 -05002933 p.link_layer_option.header.type =
2934 ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2935 p.link_layer_option.header.n_data_u64s =
2936 sizeof (p.link_layer_option) / sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002937
2938 vlib_packet_template_init (vm,
2939 &im->discover_neighbor_packet_template,
2940 &p, sizeof (p),
2941 /* alloc chunk size */ 8,
2942 "ip6 neighbor discovery");
2943 }
2944
Dave Barach203c6322016-06-26 10:29:03 -04002945 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946}
2947
2948VLIB_INIT_FUNCTION (ip6_lookup_init);
2949
2950static clib_error_t *
2951add_del_ip6_interface_table (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002952 unformat_input_t * input,
2953 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002955 vnet_main_t *vnm = vnet_get_main ();
2956 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002957 u32 sw_if_index, table_id;
2958
2959 sw_if_index = ~0;
2960
Dave Barachd7cb1b52016-12-09 09:52:16 -05002961 if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002962 {
2963 error = clib_error_return (0, "unknown interface `%U'",
2964 format_unformat_error, input);
2965 goto done;
2966 }
2967
2968 if (unformat (input, "%d", &table_id))
2969 ;
2970 else
2971 {
2972 error = clib_error_return (0, "expected table id `%U'",
2973 format_unformat_error, input);
2974 goto done;
2975 }
2976
2977 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002978 u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2979 table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002980
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002981 vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
2982 ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
Neale Ranns32e1c012016-11-22 17:07:28 +00002983
2984 fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2985 table_id);
2986
2987 vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
2988 ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002989 }
2990
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002991
Dave Barachd7cb1b52016-12-09 09:52:16 -05002992done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07002993 return error;
2994}
2995
Billy McFall0683c9c2016-10-13 08:27:31 -04002996/*?
2997 * Place the indicated interface into the supplied IPv6 FIB table (also known
2998 * as a VRF). If the FIB table does not exist, this command creates it. To
2999 * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3000 * FIB table will only be displayed if a route has been added to the table, or
3001 * an IP Address is assigned to an interface in the table (which adds a route
3002 * automatically).
3003 *
3004 * @note IP addresses added after setting the interface IP table end up in
3005 * the indicated FIB table. If the IP address is added prior to adding the
3006 * interface to the FIB table, it will NOT be part of the FIB table. Predictable
3007 * but potentially counter-intuitive results occur if you provision interface
3008 * addresses in multiple FIBs. Upon RX, packets will be processed in the last
3009 * IP table ID provisioned. It might be marginally useful to evade source RPF
3010 * drops to put an interface address into multiple FIBs.
3011 *
3012 * @cliexpar
3013 * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3014 * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3015 ?*/
3016/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003017VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3018{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003019 .path = "set interface ip6 table",
3020 .function = add_del_ip6_interface_table,
Billy McFall0683c9c2016-10-13 08:27:31 -04003021 .short_help = "set interface ip6 table <interface> <table-id>"
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022};
Billy McFall0683c9c2016-10-13 08:27:31 -04003023/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003024
Dave Barach75fc8542016-10-11 16:16:02 -04003025void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003026ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
3027 u8 * mac)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003028{
3029 ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3030 /* Invert the "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003031 ip->as_u8[8] = mac[0] ^ (1 << 1);
3032 ip->as_u8[9] = mac[1];
3033 ip->as_u8[10] = mac[2];
3034 ip->as_u8[11] = 0xFF;
3035 ip->as_u8[12] = 0xFE;
3036 ip->as_u8[13] = mac[3];
3037 ip->as_u8[14] = mac[4];
3038 ip->as_u8[15] = mac[5];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003039}
3040
Dave Barach75fc8542016-10-11 16:16:02 -04003041void
Dave Barachd7cb1b52016-12-09 09:52:16 -05003042ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3043 ip6_address_t * ip)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003044{
3045 /* Invert the previously inverted "u" bit */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003046 mac[0] = ip->as_u8[8] ^ (1 << 1);
3047 mac[1] = ip->as_u8[9];
3048 mac[2] = ip->as_u8[10];
3049 mac[3] = ip->as_u8[13];
3050 mac[4] = ip->as_u8[14];
3051 mac[5] = ip->as_u8[15];
Ed Warnickecb9cada2015-12-08 15:45:58 -07003052}
3053
Dave Barach75fc8542016-10-11 16:16:02 -04003054static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003055test_ip6_link_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003056 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003057{
3058 u8 mac[6];
3059 ip6_address_t _a, *a = &_a;
3060
3061 if (unformat (input, "%U", unformat_ethernet_address, mac))
3062 {
3063 ip6_link_local_address_from_ethernet_mac_address (a, mac);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003064 vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003065 ip6_ethernet_mac_address_from_link_local_address (mac, a);
3066 vlib_cli_output (vm, "Original MAC address: %U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003067 format_ethernet_address, mac);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003068 }
Dave Barach75fc8542016-10-11 16:16:02 -04003069
Ed Warnickecb9cada2015-12-08 15:45:58 -07003070 return 0;
3071}
3072
Billy McFall0683c9c2016-10-13 08:27:31 -04003073/*?
3074 * This command converts the given MAC Address into an IPv6 link-local
3075 * address.
3076 *
3077 * @cliexpar
3078 * Example of how to create an IPv6 link-local address:
3079 * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3080 * Link local address: fe80::14d9:e0ff:fe91:7986
3081 * Original MAC address: 16:d9:e0:91:79:86
3082 * @cliexend
3083?*/
3084/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003085VLIB_CLI_COMMAND (test_link_command, static) =
3086{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003087 .path = "test ip6 link",
Dave Barach75fc8542016-10-11 16:16:02 -04003088 .function = test_ip6_link_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003089 .short_help = "test ip6 link <mac-address>",
3090};
Billy McFall0683c9c2016-10-13 08:27:31 -04003091/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003092
Dave Barachd7cb1b52016-12-09 09:52:16 -05003093int
3094vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003096 ip6_main_t *im6 = &ip6_main;
3097 ip6_fib_t *fib;
3098 uword *p = hash_get (im6->fib_index_by_table_id, table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003099
3100 if (p == 0)
3101 return -1;
3102
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003103 fib = ip6_fib_get (p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003104
3105 fib->flow_hash_config = flow_hash_config;
3106 return 1;
3107}
3108
3109static clib_error_t *
3110set_ip6_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003111 unformat_input_t * input,
3112 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113{
3114 int matched = 0;
3115 u32 table_id = 0;
3116 u32 flow_hash_config = 0;
3117 int rv;
3118
Dave Barachd7cb1b52016-12-09 09:52:16 -05003119 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3120 {
3121 if (unformat (input, "table %d", &table_id))
3122 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003123#define _(a,v) \
3124 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05003125 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07003126#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05003127 else
3128 break;
3129 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003130
3131 if (matched == 0)
3132 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05003133 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04003134
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135 rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3136 switch (rv)
3137 {
3138 case 1:
3139 break;
3140
3141 case -1:
3142 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003143
Ed Warnickecb9cada2015-12-08 15:45:58 -07003144 default:
3145 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3146 break;
3147 }
Dave Barach75fc8542016-10-11 16:16:02 -04003148
Ed Warnickecb9cada2015-12-08 15:45:58 -07003149 return 0;
3150}
3151
Billy McFall0683c9c2016-10-13 08:27:31 -04003152/*?
3153 * Configure the set of IPv6 fields used by the flow hash.
3154 *
3155 * @cliexpar
3156 * @parblock
3157 * Example of how to set the flow hash on a given table:
Billy McFallebb9a6a2016-10-17 11:35:32 -04003158 * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3159 *
Billy McFall0683c9c2016-10-13 08:27:31 -04003160 * Example of display the configured flow hash:
3161 * @cliexstart{show ip6 fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003162 * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3163 * @::/0
3164 * unicast-ip6-chain
3165 * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3166 * [0] [@0]: dpo-drop ip6
3167 * fe80::/10
3168 * unicast-ip6-chain
3169 * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3170 * [0] [@2]: dpo-receive
3171 * ff02::1/128
3172 * unicast-ip6-chain
3173 * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3174 * [0] [@2]: dpo-receive
3175 * ff02::2/128
3176 * unicast-ip6-chain
3177 * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3178 * [0] [@2]: dpo-receive
3179 * ff02::16/128
3180 * unicast-ip6-chain
3181 * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3182 * [0] [@2]: dpo-receive
3183 * ff02::1:ff00:0/104
3184 * unicast-ip6-chain
3185 * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3186 * [0] [@2]: dpo-receive
3187 * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3188 * @::/0
3189 * unicast-ip6-chain
3190 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3191 * [0] [@0]: dpo-drop ip6
3192 * @::a:1:1:0:4/126
3193 * unicast-ip6-chain
3194 * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3195 * [0] [@4]: ipv6-glean: af_packet0
3196 * @::a:1:1:0:7/128
3197 * unicast-ip6-chain
3198 * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3199 * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3200 * fe80::/10
3201 * unicast-ip6-chain
3202 * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3203 * [0] [@2]: dpo-receive
3204 * fe80::fe:3eff:fe3e:9222/128
3205 * unicast-ip6-chain
3206 * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3207 * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3208 * ff02::1/128
3209 * unicast-ip6-chain
3210 * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3211 * [0] [@2]: dpo-receive
3212 * ff02::2/128
3213 * unicast-ip6-chain
3214 * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3215 * [0] [@2]: dpo-receive
3216 * ff02::16/128
3217 * unicast-ip6-chain
3218 * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3219 * [0] [@2]: dpo-receive
3220 * ff02::1:ff00:0/104
3221 * unicast-ip6-chain
3222 * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3223 * [0] [@2]: dpo-receive
Billy McFall0683c9c2016-10-13 08:27:31 -04003224 * @cliexend
3225 * @endparblock
3226?*/
3227/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003228VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3229{
3230 .path = "set ip6 flow-hash",
3231 .short_help =
3232 "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3233 .function = set_ip6_flow_hash_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003234};
Billy McFall0683c9c2016-10-13 08:27:31 -04003235/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003236
3237static clib_error_t *
3238show_ip6_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003239 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003240{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003241 ip6_main_t *im = &ip6_main;
3242 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003243 int i;
Dave Barach75fc8542016-10-11 16:16:02 -04003244
Ed Warnickecb9cada2015-12-08 15:45:58 -07003245 vlib_cli_output (vm, "Protocols handled by ip6_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003246 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003247 {
3248 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003249 vlib_cli_output (vm, "%d", i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003250 }
3251 return 0;
3252}
3253
3254
3255
Billy McFall0683c9c2016-10-13 08:27:31 -04003256/*?
3257 * Display the set of protocols handled by the local IPv6 stack.
3258 *
3259 * @cliexpar
3260 * Example of how to display local protocol table:
3261 * @cliexstart{show ip6 local}
3262 * Protocols handled by ip6_local
3263 * 17
3264 * 43
3265 * 58
3266 * 115
3267 * @cliexend
3268?*/
3269/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003270VLIB_CLI_COMMAND (show_ip6_local, static) =
3271{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003272 .path = "show ip6 local",
3273 .function = show_ip6_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04003274 .short_help = "show ip6 local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003275};
Billy McFall0683c9c2016-10-13 08:27:31 -04003276/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003277
Dave Barachd7cb1b52016-12-09 09:52:16 -05003278int
3279vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3280 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003281{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003282 vnet_main_t *vnm = vnet_get_main ();
3283 vnet_interface_main_t *im = &vnm->interface_main;
3284 ip6_main_t *ipm = &ip6_main;
3285 ip_lookup_main_t *lm = &ipm->lookup_main;
3286 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003287 ip6_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003288
3289 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3290 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3291
3292 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3293 return VNET_API_ERROR_NO_SUCH_ENTRY;
3294
3295 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003296 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003297
Neale Rannsdf089a82016-10-02 16:39:06 +01003298 if_addr = ip6_interface_first_address (ipm, sw_if_index, NULL);
3299
3300 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003301 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003302 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003303 .fp_len = 128,
3304 .fp_proto = FIB_PROTOCOL_IP6,
3305 .fp_addr.ip6 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003306 };
3307 u32 fib_index;
3308
Dave Barachd7cb1b52016-12-09 09:52:16 -05003309 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3310 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003311
3312
Dave Barachd7cb1b52016-12-09 09:52:16 -05003313 if (table_index != (u32) ~ 0)
3314 {
3315 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003316
Dave Barachd7cb1b52016-12-09 09:52:16 -05003317 dpo_set (&dpo,
3318 DPO_CLASSIFY,
3319 DPO_PROTO_IP6,
3320 classify_dpo_create (DPO_PROTO_IP6, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003321
Dave Barachd7cb1b52016-12-09 09:52:16 -05003322 fib_table_entry_special_dpo_add (fib_index,
3323 &pfx,
3324 FIB_SOURCE_CLASSIFY,
3325 FIB_ENTRY_FLAG_NONE, &dpo);
3326 dpo_reset (&dpo);
3327 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003328 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003329 {
3330 fib_table_entry_special_remove (fib_index,
3331 &pfx, FIB_SOURCE_CLASSIFY);
3332 }
3333 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003334
Ed Warnickecb9cada2015-12-08 15:45:58 -07003335 return 0;
3336}
3337
3338static clib_error_t *
3339set_ip6_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003340 unformat_input_t * input,
3341 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003342{
3343 u32 table_index = ~0;
3344 int table_index_set = 0;
3345 u32 sw_if_index = ~0;
3346 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003347
Dave Barachd7cb1b52016-12-09 09:52:16 -05003348 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3349 {
3350 if (unformat (input, "table-index %d", &table_index))
3351 table_index_set = 1;
3352 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3353 vnet_get_main (), &sw_if_index))
3354 ;
3355 else
3356 break;
3357 }
Dave Barach75fc8542016-10-11 16:16:02 -04003358
Ed Warnickecb9cada2015-12-08 15:45:58 -07003359 if (table_index_set == 0)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003360 return clib_error_return (0, "classify table-index must be specified");
Dave Barach75fc8542016-10-11 16:16:02 -04003361
Ed Warnickecb9cada2015-12-08 15:45:58 -07003362 if (sw_if_index == ~0)
3363 return clib_error_return (0, "interface / subif must be specified");
3364
3365 rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3366
3367 switch (rv)
3368 {
3369 case 0:
3370 break;
3371
3372 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3373 return clib_error_return (0, "No such interface");
3374
3375 case VNET_API_ERROR_NO_SUCH_ENTRY:
3376 return clib_error_return (0, "No such classifier table");
3377 }
3378 return 0;
3379}
3380
Billy McFall0683c9c2016-10-13 08:27:31 -04003381/*?
3382 * Assign a classification table to an interface. The classification
3383 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3384 * commands. Once the table is create, use this command to filter packets
3385 * on an interface.
3386 *
3387 * @cliexpar
3388 * Example of how to assign a classification table to an interface:
3389 * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3390?*/
3391/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003392VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3393{
3394 .path = "set ip6 classify",
3395 .short_help =
3396 "set ip6 classify intfc <interface> table-index <classify-idx>",
3397 .function = set_ip6_classify_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07003398};
Billy McFall0683c9c2016-10-13 08:27:31 -04003399/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003400
3401static clib_error_t *
3402ip6_config (vlib_main_t * vm, unformat_input_t * input)
3403{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003404 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003405 uword heapsize = 0;
3406 u32 tmp;
3407 u32 nbuckets = 0;
3408
Dave Barachd7cb1b52016-12-09 09:52:16 -05003409 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3410 {
3411 if (unformat (input, "hash-buckets %d", &tmp))
3412 nbuckets = tmp;
3413 else if (unformat (input, "heap-size %dm", &tmp))
3414 heapsize = ((u64) tmp) << 20;
3415 else if (unformat (input, "heap-size %dM", &tmp))
3416 heapsize = ((u64) tmp) << 20;
3417 else if (unformat (input, "heap-size %dg", &tmp))
3418 heapsize = ((u64) tmp) << 30;
3419 else if (unformat (input, "heap-size %dG", &tmp))
3420 heapsize = ((u64) tmp) << 30;
3421 else
3422 return clib_error_return (0, "unknown input '%U'",
3423 format_unformat_error, input);
3424 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07003425
3426 im->lookup_table_nbuckets = nbuckets;
3427 im->lookup_table_size = heapsize;
3428
3429 return 0;
3430}
3431
3432VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
Dave Barachd7cb1b52016-12-09 09:52:16 -05003433
3434/*
3435 * fd.io coding-style-patch-verification: ON
3436 *
3437 * Local Variables:
3438 * eval: (c-set-style "gnu")
3439 * End:
3440 */