blob: ecb3595579870c38cfd61d04565aeca8bd2f9c76 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * 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/ip4_forward.c: IP v4 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>
Ole Troan313f7e22018-04-10 16:02:51 +020042#include <vnet/ip/ip_frag.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010043#include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44#include <vnet/ethernet/arp_packet.h> /* for ethernet_arp_header_t */
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <vnet/ppp/ppp.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010046#include <vnet/srp/srp.h> /* for srp_hw_interface_class */
Dave Barachd7cb1b52016-12-09 09:52:16 -050047#include <vnet/api_errno.h> /* for API error numbers */
48#include <vnet/fib/fib_table.h> /* for FIB table and entry creation */
49#include <vnet/fib/fib_entry.h> /* for FIB table and entry creation */
50#include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
Neale Ranns0bfe5d82016-08-25 15:29:12 +010051#include <vnet/fib/ip4_fib.h>
52#include <vnet/dpo/load_balance.h>
Neale Rannsf12a83f2017-04-18 09:09:40 -070053#include <vnet/dpo/load_balance_map.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010054#include <vnet/dpo/classify_dpo.h>
Neale Ranns32e1c012016-11-22 17:07:28 +000055#include <vnet/mfib/mfib_table.h> /* for mFIB table and entry creation */
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
Vijayabhaskar Katamreddyacbde662018-01-23 13:39:40 -080057#include <vnet/ip/ip4_forward.h>
Neale Ranns25edf142019-03-22 08:12:48 +000058#include <vnet/interface_output.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
Chris Luke8e5b0412016-07-26 13:06:10 -040060/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040061 @node ip4-lookup
62
63 This is the main IPv4 lookup dispatch node.
64
65 @param vm vlib_main_t corresponding to the current thread
66 @param node vlib_node_runtime_t
67 @param frame vlib_frame_t whose contents should be dispatched
68
69 @par Graph mechanics: buffer metadata, next index usage
70
71 @em Uses:
72 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
73 - Indicates the @c sw_if_index value of the interface that the
74 packet was received on.
75 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
76 - When the value is @c ~0 then the node performs a longest prefix
77 match (LPM) for the packet destination address in the FIB attached
78 to the receive interface.
79 - Otherwise perform LPM for the packet destination address in the
80 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
81 value (0, 1, ...) and not a VRF id.
82
83 @em Sets:
84 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
85 - The lookup result adjacency index.
86
87 <em>Next Index:</em>
88 - Dispatches the packet to the node index found in
89 ip_adjacency_t @c adj->lookup_next_index
90 (where @c adj is the lookup result adjacency).
91*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020092VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
93 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070094{
Neale Rannscb54e3c2019-06-19 07:14:10 +000095 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -070096}
97
Dave Barachd7cb1b52016-12-09 09:52:16 -050098static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +010099
Neale Rannsf8686322017-11-29 02:39:53 -0800100/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500101VLIB_REGISTER_NODE (ip4_lookup_node) =
102{
Neale Rannsf8686322017-11-29 02:39:53 -0800103 .name = "ip4-lookup",
104 .vector_size = sizeof (u32),
105 .format_trace = format_ip4_lookup_trace,
106 .n_next_nodes = IP_LOOKUP_N_NEXT,
107 .next_nodes = IP4_LOOKUP_NEXT_NODES,
108};
109/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100110
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200111VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
112 vlib_node_runtime_t * node,
113 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500115 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400116 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200117 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800118 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400119 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100121 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400122 n_left = frame->n_vectors;
123 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100124
Neale Ranns3ce72b22019-05-27 08:21:32 -0400125 vlib_get_buffers (vm, from, bufs, n_left);
126
127 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400129 const load_balance_t *lb0, *lb1;
130 const ip4_header_t *ip0, *ip1;
131 u32 lbi0, hc0, lbi1, hc1;
132 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100133
Neale Ranns3ce72b22019-05-27 08:21:32 -0400134 /* Prefetch next iteration. */
135 {
136 vlib_prefetch_buffer_header (b[2], LOAD);
137 vlib_prefetch_buffer_header (b[3], LOAD);
138
139 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
140 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
141 }
142
143 ip0 = vlib_buffer_get_current (b[0]);
144 ip1 = vlib_buffer_get_current (b[1]);
145 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
146 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
147
148 lb0 = load_balance_get (lbi0);
149 lb1 = load_balance_get (lbi1);
150
151 /*
152 * this node is for via FIBs we can re-use the hash value from the
153 * to node if present.
154 * We don't want to use the same hash value at each level in the recursion
155 * graph as that would lead to polarisation
156 */
157 hc0 = hc1 = 0;
158
159 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500160 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400161 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500162 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400163 hc0 = vnet_buffer (b[0])->ip.flow_hash =
164 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700165 }
166 else
167 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400168 hc0 = vnet_buffer (b[0])->ip.flow_hash =
169 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500170 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400171 dpo0 = load_balance_get_fwd_bucket
172 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
173 }
174 else
175 {
176 dpo0 = load_balance_get_bucket_i (lb0, 0);
177 }
178 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
179 {
180 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500181 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400182 hc1 = vnet_buffer (b[1])->ip.flow_hash =
183 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500184 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700185 else
186 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400187 hc1 = vnet_buffer (b[1])->ip.flow_hash =
188 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700189 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400190 dpo1 = load_balance_get_fwd_bucket
191 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
192 }
193 else
194 {
195 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500196 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000197
Neale Ranns3ce72b22019-05-27 08:21:32 -0400198 next[0] = dpo0->dpoi_next_node;
199 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100200
Neale Ranns3ce72b22019-05-27 08:21:32 -0400201 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
202 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100203
Neale Ranns3ce72b22019-05-27 08:21:32 -0400204 vlib_increment_combined_counter
205 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
206 vlib_increment_combined_counter
207 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100208
Neale Ranns3ce72b22019-05-27 08:21:32 -0400209 b += 2;
210 next += 2;
211 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 }
213
Neale Ranns3ce72b22019-05-27 08:21:32 -0400214 while (n_left > 0)
215 {
216 const load_balance_t *lb0;
217 const ip4_header_t *ip0;
218 const dpo_id_t *dpo0;
219 u32 lbi0, hc0;
220
221 ip0 = vlib_buffer_get_current (b[0]);
222 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
223
224 lb0 = load_balance_get (lbi0);
225
226 hc0 = 0;
227 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
228 {
229 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
230 {
231 hc0 = vnet_buffer (b[0])->ip.flow_hash =
232 vnet_buffer (b[0])->ip.flow_hash >> 1;
233 }
234 else
235 {
236 hc0 = vnet_buffer (b[0])->ip.flow_hash =
237 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
238 }
239 dpo0 = load_balance_get_fwd_bucket
240 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
241 }
242 else
243 {
244 dpo0 = load_balance_get_bucket_i (lb0, 0);
245 }
246
247 next[0] = dpo0->dpoi_next_node;
248 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
249
250 vlib_increment_combined_counter
251 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
252
253 b += 1;
254 next += 1;
255 n_left -= 1;
256 }
257
258 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800259 if (node->flags & VLIB_NODE_FLAG_TRACE)
260 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
261
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100262 return frame->n_vectors;
263}
264
Neale Rannsf8686322017-11-29 02:39:53 -0800265/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500266VLIB_REGISTER_NODE (ip4_load_balance_node) =
267{
Neale Rannsf8686322017-11-29 02:39:53 -0800268 .name = "ip4-load-balance",
269 .vector_size = sizeof (u32),
270 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200271 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800272};
273/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100274
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200275#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100276/* get first interface address */
277ip4_address_t *
278ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500279 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100280{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500281 ip_lookup_main_t *lm = &im->lookup_main;
282 ip_interface_address_t *ia = 0;
283 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100284
Neale Ranns32e1c012016-11-22 17:07:28 +0000285 /* *INDENT-OFF* */
286 foreach_ip_interface_address
287 (lm, ia, sw_if_index,
288 1 /* honor unnumbered */ ,
289 ({
290 ip4_address_t * a =
291 ip_interface_address_get_address (lm, ia);
292 result = a;
293 break;
294 }));
295 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100296 if (result_ia)
297 *result_ia = result ? ia : 0;
298 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500300#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301
302static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700303ip4_add_subnet_bcast_route (u32 fib_index,
304 fib_prefix_t *pfx,
305 u32 sw_if_index)
306{
307 vnet_sw_interface_flags_t iflags;
308
309 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
310
311 fib_table_entry_special_remove(fib_index,
312 pfx,
313 FIB_SOURCE_INTERFACE);
314
315 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
316 {
317 fib_table_entry_update_one_path (fib_index, pfx,
318 FIB_SOURCE_INTERFACE,
319 FIB_ENTRY_FLAG_NONE,
320 DPO_PROTO_IP4,
321 /* No next-hop address */
322 &ADJ_BCAST_ADDR,
323 sw_if_index,
324 // invalid FIB index
325 ~0,
326 1,
327 // no out-label stack
328 NULL,
329 FIB_ROUTE_PATH_FLAG_NONE);
330 }
331 else
332 {
333 fib_table_entry_special_add(fib_index,
334 pfx,
335 FIB_SOURCE_INTERFACE,
336 (FIB_ENTRY_FLAG_DROP |
337 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
338 }
339}
340
341static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500342ip4_add_interface_prefix_routes (ip4_main_t *im,
343 u32 sw_if_index,
344 u32 fib_index,
345 ip_interface_address_t * a)
346{
347 ip_lookup_main_t *lm = &im->lookup_main;
348 ip_interface_prefix_t *if_prefix;
349 ip4_address_t *address = ip_interface_address_get_address (lm, a);
350
351 ip_interface_prefix_key_t key = {
352 .prefix = {
353 .fp_len = a->address_length,
354 .fp_proto = FIB_PROTOCOL_IP4,
355 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
356 },
357 .sw_if_index = sw_if_index,
358 };
359
360 fib_prefix_t pfx_special = {
361 .fp_proto = FIB_PROTOCOL_IP4,
362 };
363
364 /* If prefix already set on interface, just increment ref count & return */
365 if_prefix = ip_get_interface_prefix (lm, &key);
366 if (if_prefix)
367 {
368 if_prefix->ref_count += 1;
369 return;
370 }
371
372 /* New prefix - allocate a pool entry, initialize it, add to the hash */
373 pool_get (lm->if_prefix_pool, if_prefix);
374 if_prefix->ref_count = 1;
375 if_prefix->src_ia_index = a - lm->if_address_pool;
376 clib_memcpy (&if_prefix->key, &key, sizeof (key));
377 mhash_set (&lm->prefix_to_if_prefix_index, &key,
378 if_prefix - lm->if_prefix_pool, 0 /* old value */);
379
380 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
381 if (a->address_length <= 30)
382 {
383 pfx_special.fp_len = a->address_length;
384 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
385
386 /* set the glean route for the prefix */
387 fib_table_entry_update_one_path (fib_index, &pfx_special,
388 FIB_SOURCE_INTERFACE,
389 (FIB_ENTRY_FLAG_CONNECTED |
390 FIB_ENTRY_FLAG_ATTACHED),
391 DPO_PROTO_IP4,
392 /* No next-hop address */
393 NULL,
394 sw_if_index,
395 /* invalid FIB index */
396 ~0,
397 1,
398 /* no out-label stack */
399 NULL,
400 FIB_ROUTE_PATH_FLAG_NONE);
401
402 /* set a drop route for the base address of the prefix */
403 pfx_special.fp_len = 32;
404 pfx_special.fp_addr.ip4.as_u32 =
405 address->as_u32 & im->fib_masks[a->address_length];
406
407 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
408 fib_table_entry_special_add (fib_index, &pfx_special,
409 FIB_SOURCE_INTERFACE,
410 (FIB_ENTRY_FLAG_DROP |
411 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
412
413 /* set a route for the broadcast address of the prefix */
414 pfx_special.fp_len = 32;
415 pfx_special.fp_addr.ip4.as_u32 =
416 address->as_u32 | ~im->fib_masks[a->address_length];
417 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
418 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
419
420
421 }
422 /* length == 31 - add an attached route for the other address */
423 else if (a->address_length == 31)
424 {
425 pfx_special.fp_len = 32;
426 pfx_special.fp_addr.ip4.as_u32 =
427 address->as_u32 ^ clib_host_to_net_u32(1);
428
429 fib_table_entry_update_one_path (fib_index, &pfx_special,
430 FIB_SOURCE_INTERFACE,
431 (FIB_ENTRY_FLAG_ATTACHED),
432 DPO_PROTO_IP4,
433 &pfx_special.fp_addr,
434 sw_if_index,
435 /* invalid FIB index */
436 ~0,
437 1,
438 NULL,
439 FIB_ROUTE_PATH_FLAG_NONE);
440 }
441}
442
443static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444ip4_add_interface_routes (u32 sw_if_index,
445 ip4_main_t * im, u32 fib_index,
446 ip_interface_address_t * a)
447{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500448 ip_lookup_main_t *lm = &im->lookup_main;
449 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100450 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500451 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500452 .fp_proto = FIB_PROTOCOL_IP4,
453 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500456 /* set special routes for the prefix if needed */
457 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458
459 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500460 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100461 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500462 lm->classify_table_index_by_sw_if_index[sw_if_index];
463 if (classify_table_index != (u32) ~ 0)
464 {
465 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466
Dave Barachd7cb1b52016-12-09 09:52:16 -0500467 dpo_set (&dpo,
468 DPO_CLASSIFY,
469 DPO_PROTO_IP4,
470 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100471
Dave Barachd7cb1b52016-12-09 09:52:16 -0500472 fib_table_entry_special_dpo_add (fib_index,
473 &pfx,
474 FIB_SOURCE_CLASSIFY,
475 FIB_ENTRY_FLAG_NONE, &dpo);
476 dpo_reset (&dpo);
477 }
478 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100479
Neale Ranns32e1c012016-11-22 17:07:28 +0000480 fib_table_entry_update_one_path (fib_index, &pfx,
481 FIB_SOURCE_INTERFACE,
482 (FIB_ENTRY_FLAG_CONNECTED |
483 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700484 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000485 &pfx.fp_addr,
486 sw_if_index,
487 // invalid FIB index
488 ~0,
489 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500490 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491}
492
493static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500494ip4_del_interface_prefix_routes (ip4_main_t * im,
495 u32 sw_if_index,
496 u32 fib_index,
497 ip4_address_t * address,
498 u32 address_length)
499{
500 ip_lookup_main_t *lm = &im->lookup_main;
501 ip_interface_prefix_t *if_prefix;
502
503 ip_interface_prefix_key_t key = {
504 .prefix = {
505 .fp_len = address_length,
506 .fp_proto = FIB_PROTOCOL_IP4,
507 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
508 },
509 .sw_if_index = sw_if_index,
510 };
511
512 fib_prefix_t pfx_special = {
513 .fp_len = 32,
514 .fp_proto = FIB_PROTOCOL_IP4,
515 };
516
517 if_prefix = ip_get_interface_prefix (lm, &key);
518 if (!if_prefix)
519 {
520 clib_warning ("Prefix not found while deleting %U",
521 format_ip4_address_and_length, address, address_length);
522 return;
523 }
524
525 if_prefix->ref_count -= 1;
526
527 /*
528 * Routes need to be adjusted if:
529 * - deleting last intf addr in prefix
530 * - deleting intf addr used as default source address in glean adjacency
531 *
532 * We're done now otherwise
533 */
534 if ((if_prefix->ref_count > 0) &&
535 !pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
536 return;
537
538 /* length <= 30, delete glean route, first address, last address */
539 if (address_length <= 30)
540 {
541
542 /* remove glean route for prefix */
543 pfx_special.fp_addr.ip4 = *address;
544 pfx_special.fp_len = address_length;
545 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
546
547 /* if no more intf addresses in prefix, remove other special routes */
548 if (!if_prefix->ref_count)
549 {
550 /* first address in prefix */
551 pfx_special.fp_addr.ip4.as_u32 =
552 address->as_u32 & im->fib_masks[address_length];
553 pfx_special.fp_len = 32;
554
555 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
556 fib_table_entry_special_remove (fib_index,
557 &pfx_special,
558 FIB_SOURCE_INTERFACE);
559
560 /* prefix broadcast address */
561 pfx_special.fp_addr.ip4.as_u32 =
562 address->as_u32 | ~im->fib_masks[address_length];
563 pfx_special.fp_len = 32;
564
565 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
566 fib_table_entry_special_remove (fib_index,
567 &pfx_special,
568 FIB_SOURCE_INTERFACE);
569 }
570 else
571 /* default source addr just got deleted, find another */
572 {
573 ip_interface_address_t *new_src_ia = NULL;
574 ip4_address_t *new_src_addr = NULL;
575
576 new_src_addr =
577 ip4_interface_address_matching_destination
578 (im, address, sw_if_index, &new_src_ia);
579
580 if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
581
582 pfx_special.fp_len = address_length;
583 pfx_special.fp_addr.ip4 = *new_src_addr;
584
585 /* set new glean route for the prefix */
586 fib_table_entry_update_one_path (fib_index, &pfx_special,
587 FIB_SOURCE_INTERFACE,
588 (FIB_ENTRY_FLAG_CONNECTED |
589 FIB_ENTRY_FLAG_ATTACHED),
590 DPO_PROTO_IP4,
591 /* No next-hop address */
592 NULL,
593 sw_if_index,
594 /* invalid FIB index */
595 ~0,
596 1,
597 /* no out-label stack */
598 NULL,
599 FIB_ROUTE_PATH_FLAG_NONE);
600 return;
601 }
602 }
603 /* length == 31, delete attached route for the other address */
604 else if (address_length == 31)
605 {
606 pfx_special.fp_addr.ip4.as_u32 =
607 address->as_u32 ^ clib_host_to_net_u32(1);
608
609 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
610 }
611
612 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
613 pool_put (lm->if_prefix_pool, if_prefix);
614}
615
616static void
617ip4_del_interface_routes (u32 sw_if_index,
618 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100619 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500620 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500622 fib_prefix_t pfx = {
623 .fp_len = address_length,
624 .fp_proto = FIB_PROTOCOL_IP4,
625 .fp_addr.ip4 = *address,
626 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500628 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
629 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630
Dave Barachd7cb1b52016-12-09 09:52:16 -0500631 pfx.fp_len = 32;
632 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633}
634
Matthew G Smith88d29a92019-07-17 10:01:17 -0500635#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100636void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500637ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100638{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500639 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100641 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
642
643 /*
644 * enable/disable only on the 1<->0 transition
645 */
646 if (is_enable)
647 {
648 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500649 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100650 }
651 else
652 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500653 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100654 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500655 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100656 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800657 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800658 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100659
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100660
Neale Ranns8269d3d2018-01-30 09:02:20 -0800661 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400662 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000663
664 {
665 ip4_enable_disable_interface_callback_t *cb;
666 vec_foreach (cb, im->enable_disable_interface_callbacks)
667 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
668 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100669}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671static clib_error_t *
672ip4_add_del_interface_address_internal (vlib_main_t * vm,
673 u32 sw_if_index,
674 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500675 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500677 vnet_main_t *vnm = vnet_get_main ();
678 ip4_main_t *im = &ip4_main;
679 ip_lookup_main_t *lm = &im->lookup_main;
680 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500682 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683
Pavel Kotucek57808982017-08-02 08:20:19 +0200684 /* local0 interface doesn't support IP addressing */
685 if (sw_if_index == 0)
686 {
687 return
688 clib_error_create ("local0 interface doesn't support IP addressing");
689 }
690
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
692 ip4_addr_fib_init (&ip4_af, address,
693 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
694 vec_add1 (addr_fib, ip4_af);
695
Neale Ranns744902e2017-08-14 10:35:44 -0700696 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100697 * there is no support for adj-fib handling in the presence of overlapping
698 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
699 * most routers do.
700 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000701 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500702 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100704 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700705 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500706 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700707 vnet_sw_interface_t *sif;
708
709 pool_foreach(sif, vnm->interface_main.sw_interfaces,
710 ({
711 if (im->fib_index_by_sw_if_index[sw_if_index] ==
712 im->fib_index_by_sw_if_index[sif->sw_if_index])
713 {
714 foreach_ip_interface_address
715 (&im->lookup_main, ia, sif->sw_if_index,
716 0 /* honor unnumbered */ ,
717 ({
718 ip4_address_t * x =
719 ip_interface_address_get_address
720 (&im->lookup_main, ia);
721 if (ip4_destination_matches_route
722 (im, address, x, ia->address_length) ||
723 ip4_destination_matches_route (im,
724 x,
725 address,
726 address_length))
727 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500728 /* an intf may have >1 addr from the same prefix */
729 if ((sw_if_index == sif->sw_if_index) &&
730 (ia->address_length == address_length) &&
731 (x->as_u32 != address->as_u32))
732 continue;
733
734 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700735 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
736
737 return
738 clib_error_create
739 ("failed to add %U which conflicts with %U for interface %U",
740 format_ip4_address_and_length, address,
741 address_length,
742 format_ip4_address_and_length, x,
743 ia->address_length,
744 format_vnet_sw_if_index_name, vnm,
745 sif->sw_if_index);
746 }
747 }));
748 }
749 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000751 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753 elts_before = pool_elts (lm->if_address_pool);
754
755 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500756 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757 if (error)
758 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400759
Dave Barachd7cb1b52016-12-09 09:52:16 -0500760 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100761
Matthew G Smith88d29a92019-07-17 10:01:17 -0500762 /* intf addr routes are added/deleted on admin up/down */
763 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
764 {
765 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500766 ip4_del_interface_routes (sw_if_index,
767 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500768 address_length);
769 else
770 ip4_add_interface_routes (sw_if_index,
771 im, ip4_af.fib_index,
772 pool_elt_at_index
773 (lm->if_address_pool, if_address_index));
774 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700775
776 /* If pool did not grow/shrink: add duplicate address. */
777 if (elts_before != pool_elts (lm->if_address_pool))
778 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500779 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 vec_foreach (cb, im->add_del_interface_address_callbacks)
781 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 }
784
Dave Barachd7cb1b52016-12-09 09:52:16 -0500785done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 vec_free (addr_fib);
787 return error;
788}
789
790clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000791ip4_add_del_interface_address (vlib_main_t * vm,
792 u32 sw_if_index,
793 ip4_address_t * address,
794 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795{
796 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500797 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798}
799
Neale Ranns1855b8e2018-07-11 10:31:26 -0700800void
801ip4_directed_broadcast (u32 sw_if_index, u8 enable)
802{
803 ip_interface_address_t *ia;
804 ip4_main_t *im;
805
806 im = &ip4_main;
807
808 /*
809 * when directed broadcast is enabled, the subnet braodcast route will forward
810 * packets using an adjacency with a broadcast MAC. otherwise it drops
811 */
812 /* *INDENT-OFF* */
813 foreach_ip_interface_address(&im->lookup_main, ia,
814 sw_if_index, 0,
815 ({
816 if (ia->address_length <= 30)
817 {
818 ip4_address_t *ipa;
819
820 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
821
822 fib_prefix_t pfx = {
823 .fp_len = 32,
824 .fp_proto = FIB_PROTOCOL_IP4,
825 .fp_addr = {
826 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
827 },
828 };
829
830 ip4_add_subnet_bcast_route
831 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
832 sw_if_index),
833 &pfx, sw_if_index);
834 }
835 }));
836 /* *INDENT-ON* */
837}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200838#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700839
Matthew G Smith88d29a92019-07-17 10:01:17 -0500840static clib_error_t *
841ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
842{
843 ip4_main_t *im = &ip4_main;
844 ip_interface_address_t *ia;
845 ip4_address_t *a;
846 u32 is_admin_up, fib_index;
847
848 /* Fill in lookup tables with default table (0). */
849 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
850
851 vec_validate_init_empty (im->
852 lookup_main.if_address_pool_index_by_sw_if_index,
853 sw_if_index, ~0);
854
855 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
856
857 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
858
859 /* *INDENT-OFF* */
860 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
861 0 /* honor unnumbered */,
862 ({
863 a = ip_interface_address_get_address (&im->lookup_main, ia);
864 if (is_admin_up)
865 ip4_add_interface_routes (sw_if_index,
866 im, fib_index,
867 ia);
868 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500869 ip4_del_interface_routes (sw_if_index,
870 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500871 a, ia->address_length);
872 }));
873 /* *INDENT-ON* */
874
875 return 0;
876}
877
878VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
879
Dave Barachd6534602016-06-14 18:38:02 -0400880/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500881/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100882VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
883{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100885 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500886 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100887 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
888};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100889
Dave Barachd7cb1b52016-12-09 09:52:16 -0500890VNET_FEATURE_INIT (ip4_flow_classify, static) =
891{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100892 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700893 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100894 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700895};
896
Dave Barachd7cb1b52016-12-09 09:52:16 -0500897VNET_FEATURE_INIT (ip4_inacl, static) =
898{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100899 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400900 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100901 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400902};
903
Dave Barachd7cb1b52016-12-09 09:52:16 -0500904VNET_FEATURE_INIT (ip4_source_check_1, static) =
905{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100906 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400907 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100908 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400909};
910
Dave Barachd7cb1b52016-12-09 09:52:16 -0500911VNET_FEATURE_INIT (ip4_source_check_2, static) =
912{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100913 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400914 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100915 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400916};
917
Dave Barachd7cb1b52016-12-09 09:52:16 -0500918VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
919{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100920 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400921 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100922 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400923};
924
Dave Barachd7cb1b52016-12-09 09:52:16 -0500925VNET_FEATURE_INIT (ip4_policer_classify, static) =
926{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100927 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700928 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100929 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700930};
931
Dave Barachd7cb1b52016-12-09 09:52:16 -0500932VNET_FEATURE_INIT (ip4_ipsec, static) =
933{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100934 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100935 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100936 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400937};
938
Dave Barachd7cb1b52016-12-09 09:52:16 -0500939VNET_FEATURE_INIT (ip4_vpath, static) =
940{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100941 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400942 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500943 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
944};
945
Dave Barachd7cb1b52016-12-09 09:52:16 -0500946VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
947{
John Lo37682e12016-11-30 12:51:39 -0500948 .arc_name = "ip4-unicast",
949 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100950 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400951};
952
Neale Ranns8269d3d2018-01-30 09:02:20 -0800953VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500954{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100955 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800956 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400957 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100958};
959
Neale Ranns180279b2017-03-16 15:49:09 -0400960VNET_FEATURE_INIT (ip4_lookup, static) =
961{
962 .arc_name = "ip4-unicast",
963 .node_name = "ip4-lookup",
964 .runs_before = 0, /* not before any other features */
965};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100966
Dave Barachd6534602016-06-14 18:38:02 -0400967/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100968VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
969{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500970 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100971 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500972 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100973 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
974};
975
Dave Barachd7cb1b52016-12-09 09:52:16 -0500976VNET_FEATURE_INIT (ip4_vpath_mc, static) =
977{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100978 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400979 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000980 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400981};
982
Neale Ranns8269d3d2018-01-30 09:02:20 -0800983VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500984{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100985 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800986 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400987 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
988};
989
990VNET_FEATURE_INIT (ip4_lookup_mc, static) =
991{
992 .arc_name = "ip4-multicast",
993 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500994 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100995};
Dave Barach5331c722016-08-17 11:54:30 -0400996
997/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100998VNET_FEATURE_ARC_INIT (ip4_output, static) =
999{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001000 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001001 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001002 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001003 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1004};
Dave Barach5331c722016-08-17 11:54:30 -04001005
Dave Barachd7cb1b52016-12-09 09:52:16 -05001006VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1007{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001008 .arc_name = "ip4-output",
1009 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001010 .runs_before = VNET_FEATURES ("ip4-outacl"),
1011};
1012
1013VNET_FEATURE_INIT (ip4_outacl, static) =
1014{
1015 .arc_name = "ip4-output",
1016 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001017 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001018};
1019
Dave Barachd7cb1b52016-12-09 09:52:16 -05001020VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1021{
Matus Fabian08a6f012016-11-15 06:08:51 -08001022 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001023 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001024 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001025};
1026
1027/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001028VNET_FEATURE_INIT (ip4_interface_output, static) =
1029{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001030 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001031 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001032 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001033};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001034/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001035
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001037ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001039 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001041 /* Fill in lookup tables with default table (0). */
1042 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001043 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001044
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001045 if (!is_add)
1046 {
1047 ip4_main_t *im4 = &ip4_main;
1048 ip_lookup_main_t *lm4 = &im4->lookup_main;
1049 ip_interface_address_t *ia = 0;
1050 ip4_address_t *address;
1051 vlib_main_t *vm = vlib_get_main ();
1052
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001053 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001054 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001055 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001056 ({
1057 address = ip_interface_address_get_address (lm4, ia);
1058 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1059 }));
1060 /* *INDENT-ON* */
1061 }
1062
Neale Ranns8269d3d2018-01-30 09:02:20 -08001063 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001064 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065
Neale Ranns8269d3d2018-01-30 09:02:20 -08001066 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1067 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069 return /* no error */ 0;
1070}
1071
1072VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1073
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001075#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001077#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001078
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001079static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080ip4_lookup_init (vlib_main_t * vm)
1081{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001082 ip4_main_t *im = &ip4_main;
1083 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 uword i;
1085
Damjan Marion8b3191e2016-11-09 19:54:20 +01001086 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1087 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001088 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1089 return (error);
1090 if ((error = vlib_call_init_function (vm, fib_module_init)))
1091 return error;
1092 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1093 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001094
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1096 {
1097 u32 m;
1098
1099 if (i < 32)
1100 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001101 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001102 m = ~0;
1103 im->fib_masks[i] = clib_host_to_net_u32 (m);
1104 }
1105
Ed Warnickecb9cada2015-12-08 15:45:58 -07001106 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1107
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001108 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001109 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1110 FIB_SOURCE_DEFAULT_ROUTE);
1111 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1112 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001113
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001115 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 pn = pg_get_node (ip4_lookup_node.index);
1117 pn->unformat_edit = unformat_pg_ip4_header;
1118 }
1119
1120 {
1121 ethernet_arp_header_t h;
1122
Dave Barachb7b92992018-10-17 10:38:51 -04001123 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124
Ed Warnickecb9cada2015-12-08 15:45:58 -07001125#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1126#define _8(f,v) h.f = v;
1127 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1128 _16 (l3_type, ETHERNET_TYPE_IP4);
1129 _8 (n_l2_address_bytes, 6);
1130 _8 (n_l3_address_bytes, 4);
1131 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1132#undef _16
1133#undef _8
1134
Dave Barachd7cb1b52016-12-09 09:52:16 -05001135 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136 /* data */ &h,
1137 sizeof (h),
1138 /* alloc chunk size */ 8,
1139 "ip4 arp");
1140 }
1141
Dave Barach203c6322016-06-26 10:29:03 -04001142 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001143}
1144
1145VLIB_INIT_FUNCTION (ip4_lookup_init);
1146
Dave Barachd7cb1b52016-12-09 09:52:16 -05001147typedef struct
1148{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001150 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 u32 flow_hash;
1152 u32 fib_index;
1153
1154 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001155 u8 packet_data[64 - 1 * sizeof (u32)];
1156}
1157ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001159#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001160u8 *
1161format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162{
1163 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1164 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001165 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001166 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001167 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001168 format_white_space, indent,
1169 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001170 return s;
1171}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001172#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001173
Dave Barachd7cb1b52016-12-09 09:52:16 -05001174static u8 *
1175format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001176{
1177 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1178 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001179 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001180 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
John Loac8146c2016-09-27 17:44:02 -04001182 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001183 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001184 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001185 format_white_space, indent,
1186 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001187 return s;
1188}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189
Dave Barachd7cb1b52016-12-09 09:52:16 -05001190static u8 *
1191format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001192{
1193 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1194 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001195 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001196 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197
Vengada Govindanf1544482016-09-28 02:45:57 -07001198 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001199 t->fib_index, t->dpo_index, format_ip_adjacency,
1200 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001201 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001202 format_white_space, indent,
1203 format_ip_adjacency_packet_data,
Neale Rannsb069a692017-03-15 12:34:25 -04001204 t->dpo_index, t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001205 return s;
1206}
1207
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001208#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001209/* Common trace function for all ip4-forward next nodes. */
1210void
1211ip4_forward_next_trace (vlib_main_t * vm,
1212 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001213 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001214{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001215 u32 *from, n_left;
1216 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217
1218 n_left = frame->n_vectors;
1219 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001220
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221 while (n_left >= 4)
1222 {
1223 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001224 vlib_buffer_t *b0, *b1;
1225 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001226
1227 /* Prefetch next iteration. */
1228 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1229 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1230
1231 bi0 = from[0];
1232 bi1 = from[1];
1233
1234 b0 = vlib_get_buffer (vm, bi0);
1235 b1 = vlib_get_buffer (vm, bi1);
1236
1237 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1238 {
1239 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001240 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001242 t0->fib_index =
1243 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1244 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1245 vec_elt (im->fib_index_by_sw_if_index,
1246 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001247
Dave Barach178cf492018-11-13 16:34:13 -05001248 clib_memcpy_fast (t0->packet_data,
1249 vlib_buffer_get_current (b0),
1250 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251 }
1252 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1253 {
1254 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001255 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001257 t1->fib_index =
1258 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1259 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1260 vec_elt (im->fib_index_by_sw_if_index,
1261 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001262 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1263 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001264 }
1265 from += 2;
1266 n_left -= 2;
1267 }
1268
1269 while (n_left >= 1)
1270 {
1271 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001272 vlib_buffer_t *b0;
1273 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001274
1275 bi0 = from[0];
1276
1277 b0 = vlib_get_buffer (vm, bi0);
1278
1279 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1280 {
1281 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001282 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001284 t0->fib_index =
1285 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1286 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1287 vec_elt (im->fib_index_by_sw_if_index,
1288 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001289 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1290 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001291 }
1292 from += 1;
1293 n_left -= 1;
1294 }
1295}
1296
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297/* Compute TCP/UDP/ICMP4 checksum in software. */
1298u16
1299ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1300 ip4_header_t * ip0)
1301{
1302 ip_csum_t sum0;
1303 u32 ip_header_length, payload_length_host_byte_order;
Florin Corasb2215d62017-08-01 16:56:58 -07001304 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305 u16 sum16;
Dave Barachc4abafd2019-09-04 12:09:32 -04001306 u8 *data_this_buffer;
1307 u8 length_odd;
Dave Barach75fc8542016-10-11 16:16:02 -04001308
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309 /* Initialize checksum with ip header. */
1310 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001311 payload_length_host_byte_order =
1312 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1313 sum0 =
1314 clib_host_to_net_u32 (payload_length_host_byte_order +
1315 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
1317 if (BITS (uword) == 32)
1318 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001319 sum0 =
1320 ip_csum_with_carry (sum0,
1321 clib_mem_unaligned (&ip0->src_address, u32));
1322 sum0 =
1323 ip_csum_with_carry (sum0,
1324 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325 }
1326 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001327 sum0 =
1328 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329
1330 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
Dave Barachc4abafd2019-09-04 12:09:32 -04001331 data_this_buffer = (u8 *) ip0 + ip_header_length;
Neale Rannsd91c1db2017-07-31 02:30:50 -07001332 n_ip_bytes_this_buffer =
1333 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
Florin Corasb2215d62017-08-01 16:56:58 -07001334 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
1335 {
1336 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
Neale Rannsd91c1db2017-07-31 02:30:50 -07001337 n_ip_bytes_this_buffer - ip_header_length : 0;
Florin Corasb2215d62017-08-01 16:56:58 -07001338 }
Dave Barachc4abafd2019-09-04 12:09:32 -04001339
Ed Warnickecb9cada2015-12-08 15:45:58 -07001340 while (1)
1341 {
1342 sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1343 n_bytes_left -= n_this_buffer;
1344 if (n_bytes_left == 0)
1345 break;
1346
1347 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
John Lo3bc6bc22019-08-03 14:36:39 -04001348 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
1349 return 0xfefe;
1350
Dave Barachc4abafd2019-09-04 12:09:32 -04001351 length_odd = (n_this_buffer & 1);
1352
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353 p0 = vlib_get_buffer (vm, p0->next_buffer);
1354 data_this_buffer = vlib_buffer_get_current (p0);
John Lo1cf00072019-04-09 10:23:56 -04001355 n_this_buffer = clib_min (p0->current_length, n_bytes_left);
Dave Barachc4abafd2019-09-04 12:09:32 -04001356
1357 if (PREDICT_FALSE (length_odd))
1358 {
1359 /* Prepend a 0 or the resulting checksum will be incorrect. */
1360 data_this_buffer--;
1361 n_this_buffer++;
1362 n_bytes_left++;
1363 data_this_buffer[0] = 0;
1364 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001365 }
1366
Dave Barachd7cb1b52016-12-09 09:52:16 -05001367 sum16 = ~ip_csum_fold (sum0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001368 return sum16;
1369}
1370
John Lo37682e12016-11-30 12:51:39 -05001371u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1373{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001374 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1375 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 u16 sum16;
1377
1378 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1379 || ip0->protocol == IP_PROTOCOL_UDP);
1380
1381 udp0 = (void *) (ip0 + 1);
1382 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1383 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001384 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1385 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001386 return p0->flags;
1387 }
1388
1389 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1390
Damjan Marion213b5aa2017-07-13 21:19:27 +02001391 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1392 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393
1394 return p0->flags;
1395}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001396#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397
Dave Barach68b0fb02017-02-28 15:15:56 -05001398/* *INDENT-OFF* */
1399VNET_FEATURE_ARC_INIT (ip4_local) =
1400{
1401 .arc_name = "ip4-local",
1402 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001403 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001404};
1405/* *INDENT-ON* */
1406
Florin Coras20a14b92017-08-15 22:47:22 -07001407static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001408ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1409 ip4_header_t * ip, u8 is_udp, u8 * error,
1410 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001411{
1412 u32 flags0;
1413 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1414 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1415 if (is_udp)
1416 {
1417 udp_header_t *udp;
1418 u32 ip_len, udp_len;
1419 i32 len_diff;
1420 udp = ip4_next_header (ip);
1421 /* Verify UDP length. */
1422 ip_len = clib_net_to_host_u16 (ip->length);
1423 udp_len = clib_net_to_host_u16 (udp->length);
1424
1425 len_diff = ip_len - udp_len;
1426 *good_tcp_udp &= len_diff >= 0;
1427 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1428 }
1429}
1430
Florin Coras1b255522018-06-01 12:22:23 -07001431#define ip4_local_csum_is_offloaded(_b) \
1432 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1433 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1434
1435#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1436 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1437 || ip4_local_csum_is_offloaded (_b)))
1438
1439#define ip4_local_csum_is_valid(_b) \
1440 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1441 || (ip4_local_csum_is_offloaded (_b))) != 0
1442
1443static inline void
1444ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1445 ip4_header_t * ih, u8 * error)
1446{
1447 u8 is_udp, is_tcp_udp, good_tcp_udp;
1448
1449 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1450 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1451
1452 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1453 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1454 else
1455 good_tcp_udp = ip4_local_csum_is_valid (b);
1456
1457 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1458 *error = (is_tcp_udp && !good_tcp_udp
1459 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1460}
1461
1462static inline void
1463ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1464 ip4_header_t ** ih, u8 * error)
1465{
1466 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1467
1468 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1469 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1470
1471 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1472 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1473
1474 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1475 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1476
1477 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1478 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1479 {
1480 if (is_tcp_udp[0])
1481 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1482 &good_tcp_udp[0]);
1483 if (is_tcp_udp[1])
1484 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1485 &good_tcp_udp[1]);
1486 }
1487
1488 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1489 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1490 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1491 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1492}
1493
1494static inline void
1495ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1496 vlib_buffer_t * b, u16 * next, u8 error,
1497 u8 head_of_feature_arc)
1498{
1499 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1500 u32 next_index;
1501
1502 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1503 b->error = error ? error_node->errors[error] : 0;
1504 if (head_of_feature_arc)
1505 {
1506 next_index = *next;
1507 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1508 {
1509 vnet_feature_arc_start (arc_index,
1510 vnet_buffer (b)->sw_if_index[VLIB_RX],
1511 &next_index, b);
1512 *next = next_index;
1513 }
1514 }
1515}
1516
1517typedef struct
1518{
1519 ip4_address_t src;
1520 u32 lbi;
1521 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001522 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001523} ip4_local_last_check_t;
1524
1525static inline void
1526ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1527 ip4_local_last_check_t * last_check, u8 * error0)
1528{
1529 ip4_fib_mtrie_leaf_t leaf0;
1530 ip4_fib_mtrie_t *mtrie0;
1531 const dpo_id_t *dpo0;
1532 load_balance_t *lb0;
1533 u32 lbi0;
1534
1535 vnet_buffer (b)->ip.fib_index =
1536 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1537 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1538
Matthew Smith44e60462019-07-06 19:27:29 -05001539 /*
1540 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1541 * adjacency for the destination address (the local interface address).
1542 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1543 * adjacency for the source address (the remote sender's address)
1544 */
Neale Rannsbe2286b2018-12-09 12:54:51 -08001545 if (PREDICT_FALSE (last_check->first ||
1546 (last_check->src.as_u32 != ip0->src_address.as_u32)))
Florin Coras1b255522018-06-01 12:22:23 -07001547 {
1548 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1549 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1550 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1551 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1552 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1553
Matthew Smith44e60462019-07-06 19:27:29 -05001554 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1555 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001556 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001557
1558 lb0 = load_balance_get (lbi0);
1559 dpo0 = load_balance_get_bucket_i (lb0, 0);
1560
1561 /*
1562 * Must have a route to source otherwise we drop the packet.
1563 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1564 *
1565 * The checks are:
1566 * - the source is a recieve => it's from us => bogus, do this
1567 * first since it sets a different error code.
1568 * - uRPF check for any route to source - accept if passes.
1569 * - allow packets destined to the broadcast address from unknown sources
1570 */
1571
1572 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1573 && dpo0->dpoi_type == DPO_RECEIVE) ?
1574 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1575 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1576 && !fib_urpf_check_size (lb0->lb_urpf)
1577 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1578 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1579
1580 last_check->src.as_u32 = ip0->src_address.as_u32;
1581 last_check->lbi = lbi0;
1582 last_check->error = *error0;
1583 }
1584 else
1585 {
Matthew Smith44e60462019-07-06 19:27:29 -05001586 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1587 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001588 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001589 *error0 = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001590 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001591 }
1592}
1593
1594static inline void
1595ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1596 ip4_local_last_check_t * last_check, u8 * error)
1597{
1598 ip4_fib_mtrie_leaf_t leaf[2];
1599 ip4_fib_mtrie_t *mtrie[2];
1600 const dpo_id_t *dpo[2];
1601 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001602 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001603 u32 lbi[2];
1604
Neale Rannsbe2286b2018-12-09 12:54:51 -08001605 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001606 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1607 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1608
1609 vnet_buffer (b[0])->ip.fib_index =
1610 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1611 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1612 vnet_buffer (b[0])->ip.fib_index;
1613
1614 vnet_buffer (b[1])->ip.fib_index =
1615 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1616 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1617 vnet_buffer (b[1])->ip.fib_index;
1618
Matthew Smith44e60462019-07-06 19:27:29 -05001619 /*
1620 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1621 * adjacency for the destination address (the local interface address).
1622 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1623 * adjacency for the source address (the remote sender's address)
1624 */
Florin Coras1b255522018-06-01 12:22:23 -07001625 if (PREDICT_FALSE (not_last_hit))
1626 {
1627 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1628 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1629
1630 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1631 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1632
1633 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1634 &ip[0]->src_address, 2);
1635 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1636 &ip[1]->src_address, 2);
1637
1638 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1639 &ip[0]->src_address, 3);
1640 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1641 &ip[1]->src_address, 3);
1642
1643 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1644 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1645
Matthew Smith44e60462019-07-06 19:27:29 -05001646 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1647 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001648 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001649
Matthew Smith44e60462019-07-06 19:27:29 -05001650 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1651 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001652 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001653
1654 lb[0] = load_balance_get (lbi[0]);
1655 lb[1] = load_balance_get (lbi[1]);
1656
1657 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1658 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1659
1660 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1661 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1662 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1663 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1664 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1665 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1666 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1667
1668 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1669 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1670 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1671 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1672 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1673 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1674 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1675
1676 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1677 last_check->lbi = lbi[1];
1678 last_check->error = error[1];
1679 }
1680 else
1681 {
Matthew Smith44e60462019-07-06 19:27:29 -05001682 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1683 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001684 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001685
Matthew Smith44e60462019-07-06 19:27:29 -05001686 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1687 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001688 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001689
1690 error[0] = last_check->error;
1691 error[1] = last_check->error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001692 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001693 }
1694}
Florin Coras20a14b92017-08-15 22:47:22 -07001695
Florin Corasc67cfd22018-10-01 21:59:18 -07001696enum ip_local_packet_type_e
1697{
1698 IP_LOCAL_PACKET_TYPE_L4,
1699 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001700 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001701};
1702
1703/**
1704 * Determine packet type and next node.
1705 *
1706 * The expectation is that all packets that are not L4 will skip
1707 * checksums and source checks.
1708 */
1709always_inline u8
1710ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1711{
1712 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1713
Juraj Sloboda3048b632018-10-02 11:13:53 +02001714 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1715 {
1716 *next = IP_LOCAL_NEXT_REASSEMBLY;
1717 return IP_LOCAL_PACKET_TYPE_FRAG;
1718 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001719 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1720 {
1721 *next = lm->local_next_by_ip_protocol[ip->protocol];
1722 return IP_LOCAL_PACKET_TYPE_NAT;
1723 }
1724
1725 *next = lm->local_next_by_ip_protocol[ip->protocol];
1726 return IP_LOCAL_PACKET_TYPE_L4;
1727}
1728
Dave Barach68b0fb02017-02-28 15:15:56 -05001729static inline uword
1730ip4_local_inline (vlib_main_t * vm,
1731 vlib_node_runtime_t * node,
1732 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001733{
Florin Coras1b255522018-06-01 12:22:23 -07001734 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001735 vlib_node_runtime_t *error_node =
1736 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001737 u16 nexts[VLIB_FRAME_SIZE], *next;
1738 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1739 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001740 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001741
1742 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001743 /*
1744 * 0.0.0.0 can appear as the source address of an IP packet,
1745 * as can any other address, hence the need to use the 'first'
1746 * member to make sure the .lbi is initialised for the first
1747 * packet.
1748 */
Florin Coras1b255522018-06-01 12:22:23 -07001749 .src = {.as_u32 = 0},
1750 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001751 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1752 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001753 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001754
1755 from = vlib_frame_vector_args (frame);
1756 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001757
Ed Warnickecb9cada2015-12-08 15:45:58 -07001758 if (node->flags & VLIB_NODE_FLAG_TRACE)
1759 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1760
Florin Coras1b255522018-06-01 12:22:23 -07001761 vlib_get_buffers (vm, from, bufs, n_left_from);
1762 b = bufs;
1763 next = nexts;
1764
1765 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001767 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001768
Florin Coras1b255522018-06-01 12:22:23 -07001769 /* Prefetch next iteration. */
1770 {
1771 vlib_prefetch_buffer_header (b[4], LOAD);
1772 vlib_prefetch_buffer_header (b[5], LOAD);
1773
1774 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1775 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1776 }
1777
1778 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1779
1780 ip[0] = vlib_buffer_get_current (b[0]);
1781 ip[1] = vlib_buffer_get_current (b[1]);
1782
1783 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1784 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1785
Florin Corasc67cfd22018-10-01 21:59:18 -07001786 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1787 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001788
Florin Corasc67cfd22018-10-01 21:59:18 -07001789 not_batch = pt[0] ^ pt[1];
1790
1791 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001792 goto skip_checks;
1793
1794 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001795 {
Florin Coras1b255522018-06-01 12:22:23 -07001796 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1797 ip4_local_check_src_x2 (b, ip, &last_check, error);
1798 }
1799 else
1800 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001801 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001802 {
Florin Coras1b255522018-06-01 12:22:23 -07001803 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1804 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001805 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001806 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001807 {
Florin Coras1b255522018-06-01 12:22:23 -07001808 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1809 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001810 }
1811 }
1812
Florin Coras1b255522018-06-01 12:22:23 -07001813 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001814
Florin Coras1b255522018-06-01 12:22:23 -07001815 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1816 head_of_feature_arc);
1817 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1818 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001819
Florin Coras1b255522018-06-01 12:22:23 -07001820 b += 2;
1821 next += 2;
1822 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001823 }
1824
Florin Coras1b255522018-06-01 12:22:23 -07001825 while (n_left_from > 0)
1826 {
1827 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1828
1829 ip[0] = vlib_buffer_get_current (b[0]);
1830 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001831 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001832
Florin Corasc67cfd22018-10-01 21:59:18 -07001833 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001834 goto skip_check;
1835
1836 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1837 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1838
1839 skip_check:
1840
Florin Coras1b255522018-06-01 12:22:23 -07001841 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1842 head_of_feature_arc);
1843
1844 b += 1;
1845 next += 1;
1846 n_left_from -= 1;
1847 }
1848
1849 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001850 return frame->n_vectors;
1851}
1852
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001853VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1854 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001855{
1856 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1857}
1858
1859/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001860VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001861{
Dave Barach68b0fb02017-02-28 15:15:56 -05001862 .name = "ip4-local",
1863 .vector_size = sizeof (u32),
1864 .format_trace = format_ip4_forward_next_trace,
1865 .n_next_nodes = IP_LOCAL_N_NEXT,
1866 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001867 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001868 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1869 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001870 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001871 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Juraj Sloboda3048b632018-10-02 11:13:53 +02001872 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001873 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001874};
1875/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001876
Dave Barachd7cb1b52016-12-09 09:52:16 -05001877
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001878VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1879 vlib_node_runtime_t * node,
1880 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001881{
1882 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1883}
1884
1885/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001886VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001887 .name = "ip4-local-end-of-arc",
1888 .vector_size = sizeof (u32),
1889
1890 .format_trace = format_ip4_forward_next_trace,
1891 .sibling_of = "ip4-local",
1892};
1893
Dave Barach68b0fb02017-02-28 15:15:56 -05001894VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1895 .arc_name = "ip4-local",
1896 .node_name = "ip4-local-end-of-arc",
1897 .runs_before = 0, /* not before any other features */
1898};
1899/* *INDENT-ON* */
1900
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001901#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001902void
1903ip4_register_protocol (u32 protocol, u32 node_index)
1904{
1905 vlib_main_t *vm = vlib_get_main ();
1906 ip4_main_t *im = &ip4_main;
1907 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001908
1909 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001910 lm->local_next_by_ip_protocol[protocol] =
1911 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001912}
Neale Rannsb538dd82019-05-21 06:54:54 -07001913
1914void
1915ip4_unregister_protocol (u32 protocol)
1916{
1917 ip4_main_t *im = &ip4_main;
1918 ip_lookup_main_t *lm = &im->lookup_main;
1919
1920 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1921 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1922}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001923#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001924
1925static clib_error_t *
1926show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001927 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001929 ip4_main_t *im = &ip4_main;
1930 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001931 int i;
1932
1933 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001934 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001935 {
1936 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001937 {
1938 u32 node_index = vlib_get_node (vm,
1939 ip4_local_node.index)->
1940 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001941 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1942 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001943 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001944 }
1945 return 0;
1946}
1947
1948
1949
Billy McFall0683c9c2016-10-13 08:27:31 -04001950/*?
1951 * Display the set of protocols handled by the local IPv4 stack.
1952 *
1953 * @cliexpar
1954 * Example of how to display local protocol table:
1955 * @cliexstart{show ip local}
1956 * Protocols handled by ip4_local
1957 * 1
1958 * 17
1959 * 47
1960 * @cliexend
1961?*/
1962/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001963VLIB_CLI_COMMAND (show_ip_local, static) =
1964{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001965 .path = "show ip local",
1966 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001967 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001968};
Billy McFall0683c9c2016-10-13 08:27:31 -04001969/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001970
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001971always_inline uword
1972ip4_arp_inline (vlib_main_t * vm,
1973 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001974 vlib_frame_t * frame, int is_glean)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001975{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001976 vnet_main_t *vnm = vnet_get_main ();
1977 ip4_main_t *im = &ip4_main;
1978 ip_lookup_main_t *lm = &im->lookup_main;
1979 u32 *from, *to_next_drop;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001980 uword n_left_from, n_left_to_next_drop, next_index;
Dave Barach49433ad2018-08-08 17:59:03 -04001981 u32 thread_index = vm->thread_index;
Neale Rannscd35e532018-08-31 02:51:45 -07001982 u64 seed;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001983
1984 if (node->flags & VLIB_NODE_FLAG_TRACE)
1985 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1986
Neale Rannsc8352bc2018-08-29 10:23:58 -07001987 seed = throttle_seed (&im->arp_throttle, thread_index, vlib_time_now (vm));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001988
1989 from = vlib_frame_vector_args (frame);
1990 n_left_from = frame->n_vectors;
1991 next_index = node->cached_next_index;
1992 if (next_index == IP4_ARP_NEXT_DROP)
Dave Barachd7cb1b52016-12-09 09:52:16 -05001993 next_index = IP4_ARP_N_NEXT; /* point to first interface */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994
1995 while (n_left_from > 0)
1996 {
1997 vlib_get_next_frame (vm, node, IP4_ARP_NEXT_DROP,
1998 to_next_drop, n_left_to_next_drop);
1999
2000 while (n_left_from > 0 && n_left_to_next_drop > 0)
2001 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002002 u32 pi0, bi0, adj_index0, sw_if_index0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002003 ip_adjacency_t *adj0;
Eyal Baribf9f02c2018-10-31 13:19:11 +02002004 vlib_buffer_t *p0, *b0;
2005 ip4_address_t resolve0;
2006 ethernet_arp_header_t *h0;
2007 vnet_hw_interface_t *hw_if0;
Neale Rannscd35e532018-08-31 02:51:45 -07002008 u64 r0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002009
2010 pi0 = from[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002011 p0 = vlib_get_buffer (vm, pi0);
2012
Ed Warnickecb9cada2015-12-08 15:45:58 -07002013 from += 1;
2014 n_left_from -= 1;
2015 to_next_drop[0] = pi0;
2016 to_next_drop += 1;
2017 n_left_to_next_drop -= 1;
2018
Eyal Baribf9f02c2018-10-31 13:19:11 +02002019 adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2020 adj0 = adj_get (adj_index0);
2021
2022 if (is_glean)
2023 {
2024 /* resolve the packet's destination */
2025 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
2026 resolve0 = ip0->dst_address;
2027 }
2028 else
2029 {
2030 /* resolve the incomplete adj */
2031 resolve0 = adj0->sub_type.nbr.next_hop.ip4;
2032 }
2033
2034 /* combine the address and interface for the hash key */
2035 sw_if_index0 = adj0->rewrite_header.sw_if_index;
2036 r0 = (u64) resolve0.data_u32 << 32;
2037 r0 |= sw_if_index0;
2038
2039 if (throttle_check (&im->arp_throttle, thread_index, r0, seed))
2040 {
2041 p0->error = node->errors[IP4_ARP_ERROR_THROTTLED];
2042 continue;
2043 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044
Neale Rannsb80c5362016-10-08 13:03:40 +01002045 /*
2046 * the adj has been updated to a rewrite but the node the DPO that got
2047 * us here hasn't - yet. no big deal. we'll drop while we wait.
2048 */
2049 if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
Eyal Baribf9f02c2018-10-31 13:19:11 +02002050 {
2051 p0->error = node->errors[IP4_ARP_ERROR_RESOLVED];
2052 continue;
2053 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002054
Dave Barachd7cb1b52016-12-09 09:52:16 -05002055 /*
2056 * Can happen if the control-plane is programming tables
2057 * with traffic flowing; at least that's today's lame excuse.
2058 */
Neale Ranns32e1c012016-11-22 17:07:28 +00002059 if ((is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
2060 || (!is_glean && adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002061 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002062 p0->error = node->errors[IP4_ARP_ERROR_NON_ARP_ADJ];
Eyal Baribf9f02c2018-10-31 13:19:11 +02002063 continue;
2064 }
2065 /* Send ARP request. */
2066 h0 =
2067 vlib_packet_template_get_packet (vm,
2068 &im->ip4_arp_request_packet_template,
2069 &bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002070 /* Seems we're out of buffers */
2071 if (PREDICT_FALSE (!h0))
2072 {
2073 p0->error = node->errors[IP4_ARP_ERROR_NO_BUFFERS];
2074 continue;
2075 }
2076
Dave Barachb19bf8d2019-05-31 08:41:34 -04002077 b0 = vlib_get_buffer (vm, bi0);
2078
2079 /* copy the persistent fields from the original */
2080 clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
2081
Eyal Baribf9f02c2018-10-31 13:19:11 +02002082 /* Add rewrite/encap string for ARP packet. */
2083 vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
2084
2085 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
2086
2087 /* Src ethernet address in ARP header. */
Neale Ranns37029302018-08-10 05:30:06 -07002088 mac_address_from_bytes (&h0->ip4_over_ethernet[0].mac,
2089 hw_if0->hw_address);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002090 if (is_glean)
2091 {
2092 /* The interface's source address is stashed in the Glean Adj */
2093 h0->ip4_over_ethernet[0].ip4 =
2094 adj0->sub_type.glean.receive_addr.ip4;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002095 }
Dave Barachd7cb1b52016-12-09 09:52:16 -05002096 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002097 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002098 /* Src IP address in ARP header. */
2099 if (ip4_src_address_for_packet (lm, sw_if_index0,
2100 &h0->ip4_over_ethernet[0].ip4))
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002101 {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002102 /* No source address available */
2103 p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS];
2104 vlib_buffer_free (vm, &bi0, 1);
2105 continue;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002106 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002107 }
Eyal Baribf9f02c2018-10-31 13:19:11 +02002108 h0->ip4_over_ethernet[1].ip4 = resolve0;
2109
2110 p0->error = node->errors[IP4_ARP_ERROR_REQUEST_SENT];
2111
2112 vlib_buffer_copy_trace_flag (vm, p0, bi0);
Eyal Baribf9f02c2018-10-31 13:19:11 +02002113 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
2114 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
2115
2116 vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
2117
2118 vlib_set_next_frame_buffer (vm, node,
2119 adj0->rewrite_header.next_index, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002120 }
2121
2122 vlib_put_next_frame (vm, node, IP4_ARP_NEXT_DROP, n_left_to_next_drop);
2123 }
2124
2125 return frame->n_vectors;
2126}
2127
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002128VLIB_NODE_FN (ip4_arp_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2129 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002130{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002131 return (ip4_arp_inline (vm, node, frame, 0));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002132}
2133
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002134VLIB_NODE_FN (ip4_glean_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2135 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002136{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002137 return (ip4_arp_inline (vm, node, frame, 1));
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002138}
2139
Dave Barachd7cb1b52016-12-09 09:52:16 -05002140static char *ip4_arp_error_strings[] = {
Eyal Baribf9f02c2018-10-31 13:19:11 +02002141 [IP4_ARP_ERROR_THROTTLED] = "ARP requests throttled",
2142 [IP4_ARP_ERROR_RESOLVED] = "ARP requests resolved",
2143 [IP4_ARP_ERROR_NO_BUFFERS] = "ARP requests out of buffer",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002144 [IP4_ARP_ERROR_REQUEST_SENT] = "ARP requests sent",
2145 [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies",
Pierre Pfisterd076f192016-06-22 12:58:30 +01002146 [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002147};
2148
Neale Rannsf8686322017-11-29 02:39:53 -08002149/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002150VLIB_REGISTER_NODE (ip4_arp_node) =
2151{
Neale Rannsf8686322017-11-29 02:39:53 -08002152 .name = "ip4-arp",
2153 .vector_size = sizeof (u32),
2154 .format_trace = format_ip4_forward_next_trace,
2155 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2156 .error_strings = ip4_arp_error_strings,
2157 .n_next_nodes = IP4_ARP_N_NEXT,
2158 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002159 {
Neale Rannsf8686322017-11-29 02:39:53 -08002160 [IP4_ARP_NEXT_DROP] = "error-drop",
2161 },
2162};
Ed Warnickecb9cada2015-12-08 15:45:58 -07002163
Dave Barachd7cb1b52016-12-09 09:52:16 -05002164VLIB_REGISTER_NODE (ip4_glean_node) =
2165{
Neale Rannsf8686322017-11-29 02:39:53 -08002166 .name = "ip4-glean",
2167 .vector_size = sizeof (u32),
2168 .format_trace = format_ip4_forward_next_trace,
2169 .n_errors = ARRAY_LEN (ip4_arp_error_strings),
2170 .error_strings = ip4_arp_error_strings,
2171 .n_next_nodes = IP4_ARP_N_NEXT,
2172 .next_nodes = {
2173 [IP4_ARP_NEXT_DROP] = "error-drop",
2174 },
2175};
2176/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002177
Ed Warnickecb9cada2015-12-08 15:45:58 -07002178#define foreach_notrace_ip4_arp_error \
Eyal Baribf9f02c2018-10-31 13:19:11 +02002179_(THROTTLED) \
2180_(RESOLVED) \
2181_(NO_BUFFERS) \
Ed Warnickecb9cada2015-12-08 15:45:58 -07002182_(REQUEST_SENT) \
Eyal Baribf9f02c2018-10-31 13:19:11 +02002183_(NON_ARP_ADJ) \
2184_(NO_SOURCE_ADDRESS)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002185
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002186static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05002187arp_notrace_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002188{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002189 vlib_node_runtime_t *rt = vlib_node_get_runtime (vm, ip4_arp_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002190
2191 /* don't trace ARP request packets */
2192#define _(a) \
2193 vnet_pcap_drop_trace_filter_add_del \
2194 (rt->errors[IP4_ARP_ERROR_##a], \
2195 1 /* is_add */);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002196 foreach_notrace_ip4_arp_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002197#undef _
2198 return 0;
2199}
2200
Dave Barachd7cb1b52016-12-09 09:52:16 -05002201VLIB_INIT_FUNCTION (arp_notrace_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002202
2203
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002204#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07002205/* Send an ARP request to see if given destination is reachable on given interface. */
2206clib_error_t *
John Lo86376342018-06-11 20:14:49 -04002207ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index,
2208 u8 refresh)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002209{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002210 vnet_main_t *vnm = vnet_get_main ();
2211 ip4_main_t *im = &ip4_main;
2212 ethernet_arp_header_t *h;
2213 ip4_address_t *src;
2214 ip_interface_address_t *ia;
2215 ip_adjacency_t *adj;
2216 vnet_hw_interface_t *hi;
2217 vnet_sw_interface_t *si;
2218 vlib_buffer_t *b;
Neale Ranns7a272742017-05-30 02:08:14 -07002219 adj_index_t ai;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002220 u32 bi = 0;
John Lo86376342018-06-11 20:14:49 -04002221 u8 unicast_rewrite = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222
2223 si = vnet_get_sw_interface (vnm, sw_if_index);
2224
2225 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
2226 {
2227 return clib_error_return (0, "%U: interface %U down",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002228 format_ip4_address, dst,
2229 format_vnet_sw_if_index_name, vnm,
2230 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002231 }
2232
Dave Barachd7cb1b52016-12-09 09:52:16 -05002233 src =
2234 ip4_interface_address_matching_destination (im, dst, sw_if_index, &ia);
2235 if (!src)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002236 {
2237 vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
Dave Barach75fc8542016-10-11 16:16:02 -04002238 return clib_error_return
Neale Ranns32e1c012016-11-22 17:07:28 +00002239 (0,
2240 "no matching interface address for destination %U (interface %U)",
2241 format_ip4_address, dst, format_vnet_sw_if_index_name, vnm,
2242 sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002243 }
2244
Neale Ranns7a272742017-05-30 02:08:14 -07002245 h = vlib_packet_template_get_packet (vm,
2246 &im->ip4_arp_request_packet_template,
2247 &bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002248
John Lo084606b2018-06-19 15:27:48 -04002249 if (!h)
2250 return clib_error_return (0, "ARP request packet allocation failed");
2251
Ed Warnickecb9cada2015-12-08 15:45:58 -07002252 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
Pavel Kotucek57808982017-08-02 08:20:19 +02002253 if (PREDICT_FALSE (!hi->hw_address))
2254 {
2255 return clib_error_return (0, "%U: interface %U do not support ip probe",
2256 format_ip4_address, dst,
2257 format_vnet_sw_if_index_name, vnm,
2258 sw_if_index);
2259 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002260
Neale Ranns37029302018-08-10 05:30:06 -07002261 mac_address_from_bytes (&h->ip4_over_ethernet[0].mac, hi->hw_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002262
2263 h->ip4_over_ethernet[0].ip4 = src[0];
2264 h->ip4_over_ethernet[1].ip4 = dst[0];
2265
2266 b = vlib_get_buffer (vm, bi);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002267 vnet_buffer (b)->sw_if_index[VLIB_RX] =
2268 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002269
Dave Barach59b25652017-09-10 15:04:27 -04002270 ip46_address_t nh = {
2271 .ip4 = *dst,
2272 };
2273
2274 ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4,
2275 VNET_LINK_IP4, &nh, sw_if_index);
2276 adj = adj_get (ai);
2277
2278 /* Peer has been previously resolved, retrieve glean adj instead */
2279 if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
2280 {
John Lo86376342018-06-11 20:14:49 -04002281 if (refresh)
2282 unicast_rewrite = 1;
2283 else
2284 {
2285 adj_unlock (ai);
2286 ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP4,
2287 VNET_LINK_IP4, sw_if_index, &nh);
2288 adj = adj_get (ai);
2289 }
Dave Barach59b25652017-09-10 15:04:27 -04002290 }
2291
Ed Warnickecb9cada2015-12-08 15:45:58 -07002292 /* Add encapsulation string for software interface (e.g. ethernet header). */
2293 vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
John Lo86376342018-06-11 20:14:49 -04002294 if (unicast_rewrite)
2295 {
2296 u16 *etype = vlib_buffer_get_current (b) - 2;
2297 etype[0] = clib_host_to_net_u16 (ETHERNET_TYPE_ARP);
2298 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002299 vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
2300
2301 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002302 vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
2303 u32 *to_next = vlib_frame_vector_args (f);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 to_next[0] = bi;
2305 f->n_vectors = 1;
2306 vlib_put_frame_to_node (vm, hi->output_node_index, f);
2307 }
2308
Neale Ranns7a272742017-05-30 02:08:14 -07002309 adj_unlock (ai);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310 return /* no error */ 0;
2311}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002312#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002313
Dave Barachd7cb1b52016-12-09 09:52:16 -05002314typedef enum
2315{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002316 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04002317 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02002318 IP4_REWRITE_NEXT_FRAGMENT,
2319 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002320} ip4_rewrite_next_t;
2321
Neale Ranns889fe942017-06-01 05:43:19 -04002322/**
2323 * This bits of an IPv4 address to mask to construct a multicast
2324 * MAC address
2325 */
2326#if CLIB_ARCH_IS_BIG_ENDIAN
2327#define IP4_MCAST_ADDR_MASK 0x007fffff
2328#else
2329#define IP4_MCAST_ADDR_MASK 0xffff7f00
2330#endif
2331
Ole Troan8a9c8f12018-05-18 11:01:31 +02002332always_inline void
2333ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002334 u16 adj_packet_bytes, bool df, u16 * next, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02002335{
2336 if (packet_len > adj_packet_bytes)
2337 {
2338 *error = IP4_ERROR_MTU_EXCEEDED;
2339 if (df)
2340 {
2341 icmp4_error_set_vnet_buffer
2342 (b, ICMP4_destination_unreachable,
2343 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
2344 adj_packet_bytes);
2345 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2346 }
2347 else
2348 {
Ole Troan313f7e22018-04-10 16:02:51 +02002349 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02002350 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Ole Troanb3655e52018-08-16 22:08:49 +02002351 IP4_FRAG_NEXT_IP4_REWRITE, 0);
Ole Troan313f7e22018-04-10 16:02:51 +02002352 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02002353 }
2354 }
2355}
2356
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002357/* Decrement TTL & update checksum.
2358 Works either endian, so no need for byte swap. */
2359static_always_inline void
2360ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2361 u32 * error)
2362{
2363 i32 ttl;
2364 u32 checksum;
2365 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2366 {
2367 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2368 return;
2369 }
2370
2371 ttl = ip->ttl;
2372
2373 /* Input node should have reject packets with ttl 0. */
2374 ASSERT (ip->ttl > 0);
2375
2376 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2377 checksum += checksum >= 0xffff;
2378
2379 ip->checksum = checksum;
2380 ttl -= 1;
2381 ip->ttl = ttl;
2382
2383 /*
2384 * If the ttl drops below 1 when forwarding, generate
2385 * an ICMP response.
2386 */
2387 if (PREDICT_FALSE (ttl <= 0))
2388 {
2389 *error = IP4_ERROR_TIME_EXPIRED;
2390 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2391 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2392 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2393 0);
2394 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2395 }
2396
2397 /* Verify checksum. */
2398 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2399 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2400}
2401
2402
Ed Warnickecb9cada2015-12-08 15:45:58 -07002403always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002404ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2405 vlib_node_runtime_t * node,
2406 vlib_frame_t * frame,
2407 int do_counters, int is_midchain, int is_mcast,
2408 int do_gso)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002410 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2411 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002412 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2413 u16 nexts[VLIB_FRAME_SIZE], *next;
2414 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002415 vlib_node_runtime_t *error_node =
2416 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417
2418 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002419 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002420
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002421 vlib_get_buffers (vm, from, bufs, n_left_from);
2422 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2423
2424 if (n_left_from >= 6)
2425 {
2426 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002427 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002428 vlib_prefetch_buffer_header (bufs[i], LOAD);
2429 }
2430
2431 next = nexts;
2432 b = bufs;
2433 while (n_left_from >= 8)
2434 {
2435 ip_adjacency_t *adj0, *adj1;
2436 ip4_header_t *ip0, *ip1;
2437 u32 rw_len0, error0, adj_index0;
2438 u32 rw_len1, error1, adj_index1;
2439 u32 tx_sw_if_index0, tx_sw_if_index1;
2440 u8 *p;
2441
2442 vlib_prefetch_buffer_header (b[6], LOAD);
2443 vlib_prefetch_buffer_header (b[7], LOAD);
2444
2445 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2446 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2447
2448 /*
2449 * pre-fetch the per-adjacency counters
2450 */
2451 if (do_counters)
2452 {
2453 vlib_prefetch_combined_counter (&adjacency_counters,
2454 thread_index, adj_index0);
2455 vlib_prefetch_combined_counter (&adjacency_counters,
2456 thread_index, adj_index1);
2457 }
2458
2459 ip0 = vlib_buffer_get_current (b[0]);
2460 ip1 = vlib_buffer_get_current (b[1]);
2461
2462 error0 = error1 = IP4_ERROR_NONE;
2463
2464 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2465 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2466
2467 /* Rewrite packet header and updates lengths. */
2468 adj0 = adj_get (adj_index0);
2469 adj1 = adj_get (adj_index1);
2470
2471 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2472 rw_len0 = adj0[0].rewrite_header.data_bytes;
2473 rw_len1 = adj1[0].rewrite_header.data_bytes;
2474 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2475 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2476
2477 p = vlib_buffer_get_current (b[2]);
2478 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2479 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2480
2481 p = vlib_buffer_get_current (b[3]);
2482 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2483 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2484
2485 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002486 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2487 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2488
2489 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2490 ip0_len = gso_mtu_sz (b[0]);
2491 if (do_gso && (b[1]->flags & VNET_BUFFER_F_GSO))
2492 ip1_len = gso_mtu_sz (b[1]);
2493
2494 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002495 adj0[0].rewrite_header.max_l3_packet_bytes,
2496 ip0->flags_and_fragment_offset &
2497 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2498 next + 0, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002499 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002500 adj1[0].rewrite_header.max_l3_packet_bytes,
2501 ip1->flags_and_fragment_offset &
2502 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2503 next + 1, &error1);
2504
2505 if (is_mcast)
2506 {
2507 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2508 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2509 IP4_ERROR_SAME_INTERFACE : error0);
2510 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2511 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2512 IP4_ERROR_SAME_INTERFACE : error1);
2513 }
2514
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002515 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002516 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002517 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2518 {
2519 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002520 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002521 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2522 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2523
2524 if (PREDICT_FALSE
2525 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2526 vnet_feature_arc_start (lm->output_feature_arc_index,
2527 tx_sw_if_index0, &next_index, b[0]);
2528 next[0] = next_index;
2529 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002530 else
2531 {
2532 b[0]->error = error_node->errors[error0];
2533 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002534 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2535 {
2536 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002537 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002538
2539 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2540 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2541
2542 if (PREDICT_FALSE
2543 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2544 vnet_feature_arc_start (lm->output_feature_arc_index,
2545 tx_sw_if_index1, &next_index, b[1]);
2546 next[1] = next_index;
2547 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002548 else
2549 {
2550 b[1]->error = error_node->errors[error1];
2551 }
Neale Ranns25edf142019-03-22 08:12:48 +00002552 if (is_midchain)
2553 {
2554 calc_checksums (vm, b[0]);
2555 calc_checksums (vm, b[1]);
2556 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002557 /* Guess we are only writing on simple Ethernet header. */
2558 vnet_rewrite_two_headers (adj0[0], adj1[0],
2559 ip0, ip1, sizeof (ethernet_header_t));
2560
2561 /*
2562 * Bump the per-adjacency counters
2563 */
2564 if (do_counters)
2565 {
2566 vlib_increment_combined_counter
2567 (&adjacency_counters,
2568 thread_index,
2569 adj_index0, 1, vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2570
2571 vlib_increment_combined_counter
2572 (&adjacency_counters,
2573 thread_index,
2574 adj_index1, 1, vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
2575 }
2576
2577 if (is_midchain)
2578 {
Neale Ranns25edf142019-03-22 08:12:48 +00002579 if (adj0->sub_type.midchain.fixup_func)
2580 adj0->sub_type.midchain.fixup_func
2581 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2582 if (adj1->sub_type.midchain.fixup_func)
2583 adj1->sub_type.midchain.fixup_func
2584 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002585 }
2586
2587 if (is_mcast)
2588 {
2589 /*
2590 * copy bytes from the IP address into the MAC rewrite
2591 */
2592 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2593 adj0->rewrite_header.dst_mcast_offset,
2594 &ip0->dst_address.as_u32, (u8 *) ip0);
2595 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
Zhiyong Yangb2ecc5d2018-12-13 14:09:40 +08002596 adj1->rewrite_header.dst_mcast_offset,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002597 &ip1->dst_address.as_u32, (u8 *) ip1);
2598 }
2599
2600 next += 2;
2601 b += 2;
2602 n_left_from -= 2;
2603 }
2604
Ed Warnickecb9cada2015-12-08 15:45:58 -07002605 while (n_left_from > 0)
2606 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002607 ip_adjacency_t *adj0;
2608 ip4_header_t *ip0;
2609 u32 rw_len0, adj_index0, error0;
2610 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002611
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002612 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2613
2614 adj0 = adj_get (adj_index0);
2615
2616 if (do_counters)
2617 vlib_prefetch_combined_counter (&adjacency_counters,
2618 thread_index, adj_index0);
2619
2620 ip0 = vlib_buffer_get_current (b[0]);
2621
2622 error0 = IP4_ERROR_NONE;
2623
2624 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2625
2626
2627 /* Update packet buffer attributes/set output interface. */
2628 rw_len0 = adj0[0].rewrite_header.data_bytes;
2629 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2630
2631 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002632 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2633 if (do_gso && (b[0]->flags & VNET_BUFFER_F_GSO))
2634 ip0_len = gso_mtu_sz (b[0]);
2635
2636 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002637 adj0[0].rewrite_header.max_l3_packet_bytes,
2638 ip0->flags_and_fragment_offset &
2639 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
2640 next + 0, &error0);
2641
2642 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002643 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002644 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2645 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2646 IP4_ERROR_SAME_INTERFACE : error0);
2647 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002648
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002649 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002650 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002651 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2652 {
2653 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002654 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002655 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2656 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002657
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002658 if (PREDICT_FALSE
2659 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2660 vnet_feature_arc_start (lm->output_feature_arc_index,
2661 tx_sw_if_index0, &next_index, b[0]);
2662 next[0] = next_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002663 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002664 else
2665 {
2666 b[0]->error = error_node->errors[error0];
2667 }
Neale Ranns25edf142019-03-22 08:12:48 +00002668 if (is_midchain)
2669 {
2670 calc_checksums (vm, b[0]);
2671 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002672 /* Guess we are only writing on simple Ethernet header. */
2673 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2674
2675 if (do_counters)
2676 vlib_increment_combined_counter
2677 (&adjacency_counters,
2678 thread_index, adj_index0, 1,
2679 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2680
2681 if (is_midchain)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002682 {
Neale Ranns25edf142019-03-22 08:12:48 +00002683 if (adj0->sub_type.midchain.fixup_func)
2684 adj0->sub_type.midchain.fixup_func
2685 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002686 }
Dave Barach75fc8542016-10-11 16:16:02 -04002687
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002688 if (is_mcast)
2689 {
2690 /*
2691 * copy bytes from the IP address into the MAC rewrite
2692 */
2693 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2694 adj0->rewrite_header.dst_mcast_offset,
2695 &ip0->dst_address.as_u32, (u8 *) ip0);
2696 }
2697
2698 next += 1;
2699 b += 1;
2700 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002701 }
2702
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002703
Ed Warnickecb9cada2015-12-08 15:45:58 -07002704 /* Need to do trace after rewrites to pick up new packet data. */
2705 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002706 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002707
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002708 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002709 return frame->n_vectors;
2710}
2711
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002712always_inline uword
2713ip4_rewrite_inline (vlib_main_t * vm,
2714 vlib_node_runtime_t * node,
2715 vlib_frame_t * frame,
2716 int do_counters, int is_midchain, int is_mcast)
2717{
2718 vnet_main_t *vnm = vnet_get_main ();
2719 if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
2720 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2721 is_midchain, is_mcast,
2722 1 /* do_gso */ );
2723 else
2724 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2725 is_midchain, is_mcast,
2726 0 /* no do_gso */ );
2727}
2728
Dave Barach132d51d2016-07-07 10:10:17 -04002729
Neale Rannsf06aea52016-11-29 06:51:37 -08002730/** @brief IPv4 rewrite node.
2731 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002732
2733 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2734 header checksum, fetch the ip adjacency, check the outbound mtu,
2735 apply the adjacency rewrite, and send pkts to the adjacency
2736 rewrite header's rewrite_next_index.
2737
2738 @param vm vlib_main_t corresponding to the current thread
2739 @param node vlib_node_runtime_t
2740 @param frame vlib_frame_t whose contents should be dispatched
2741
2742 @par Graph mechanics: buffer metadata, next index usage
2743
2744 @em Uses:
2745 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2746 - the rewrite adjacency index
2747 - <code>adj->lookup_next_index</code>
2748 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002749 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002750 - <code>adj->rewrite_header</code>
2751 - Rewrite string length, rewrite string, next_index
2752
2753 @em Sets:
2754 - <code>b->current_data, b->current_length</code>
2755 - Updated net of applying the rewrite string
2756
2757 <em>Next Indices:</em>
2758 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002759 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002760*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002761
2762VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2763 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002764{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002765 if (adj_are_counters_enabled ())
2766 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2767 else
2768 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002769}
2770
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002771VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2772 vlib_node_runtime_t * node,
2773 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002774{
2775 if (adj_are_counters_enabled ())
2776 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2777 else
2778 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2779}
2780
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002781VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2782 vlib_node_runtime_t * node,
2783 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002784{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002785 if (adj_are_counters_enabled ())
2786 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2787 else
2788 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002789}
2790
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002791VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2792 vlib_node_runtime_t * node,
2793 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002794{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002795 if (adj_are_counters_enabled ())
2796 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2797 else
2798 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002799}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002800
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002801VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2802 vlib_node_runtime_t * node,
2803 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002804{
2805 if (adj_are_counters_enabled ())
2806 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2807 else
2808 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2809}
2810
Neale Ranns32e1c012016-11-22 17:07:28 +00002811/* *INDENT-OFF* */
2812VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002813 .name = "ip4-rewrite",
2814 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002815
Neale Ranns32e1c012016-11-22 17:07:28 +00002816 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002817
Ole Troan313f7e22018-04-10 16:02:51 +02002818 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002819 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002820 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002821 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002822 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002823 },
2824};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002825
2826VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002827 .name = "ip4-rewrite-bcast",
2828 .vector_size = sizeof (u32),
2829
2830 .format_trace = format_ip4_rewrite_trace,
2831 .sibling_of = "ip4-rewrite",
2832};
Neale Ranns32e1c012016-11-22 17:07:28 +00002833
2834VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002835 .name = "ip4-rewrite-mcast",
2836 .vector_size = sizeof (u32),
2837
2838 .format_trace = format_ip4_rewrite_trace,
2839 .sibling_of = "ip4-rewrite",
2840};
Neale Ranns32e1c012016-11-22 17:07:28 +00002841
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002842VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002843 .name = "ip4-mcast-midchain",
2844 .vector_size = sizeof (u32),
2845
2846 .format_trace = format_ip4_rewrite_trace,
2847 .sibling_of = "ip4-rewrite",
2848};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002849
Neale Ranns32e1c012016-11-22 17:07:28 +00002850VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002851 .name = "ip4-midchain",
2852 .vector_size = sizeof (u32),
2853 .format_trace = format_ip4_forward_next_trace,
2854 .sibling_of = "ip4-rewrite",
2855};
Neale Ranns32e1c012016-11-22 17:07:28 +00002856/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002857
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002858static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002859ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2860{
2861 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002862 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002863 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002864
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002865 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002866
Neale Ranns04a75e32017-03-23 06:46:01 -07002867 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002868 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2869 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002870
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002871 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002872
Dave Barachd7cb1b52016-12-09 09:52:16 -05002873 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002874}
Dave Barach75fc8542016-10-11 16:16:02 -04002875
Ed Warnickecb9cada2015-12-08 15:45:58 -07002876static clib_error_t *
2877test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879{
Billy McFall309fe062016-10-14 07:37:33 -04002880 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002881 u32 table_id = 0;
2882 f64 count = 1;
2883 u32 n;
2884 int i;
2885 ip4_address_t ip4_base_address;
2886 u64 errors = 0;
2887
Dave Barachd7cb1b52016-12-09 09:52:16 -05002888 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2889 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002890 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002891 {
2892 /* Make sure the entry exists. */
2893 fib = ip4_fib_get (table_id);
2894 if ((fib) && (fib->index != table_id))
2895 return clib_error_return (0, "<fib-index> %d does not exist",
2896 table_id);
2897 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002898 else if (unformat (input, "count %f", &count))
2899 ;
2900
2901 else if (unformat (input, "%U",
2902 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002904 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002905 return clib_error_return (0, "unknown input `%U'",
2906 format_unformat_error, input);
2907 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002908
2909 n = count;
2910
2911 for (i = 0; i < n; i++)
2912 {
2913 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002914 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915
Dave Barach75fc8542016-10-11 16:16:02 -04002916 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 clib_host_to_net_u32 (1 +
2918 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002919 }
2920
Dave Barach75fc8542016-10-11 16:16:02 -04002921 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002922 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2923 else
2924 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2925
2926 return 0;
2927}
2928
Billy McFall0683c9c2016-10-13 08:27:31 -04002929/*?
2930 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2931 * given FIB table to determine if there is a conflict with the
2932 * adjacency table. The fib-id can be determined by using the
2933 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2934 * of 0 is used.
2935 *
2936 * @todo This command uses fib-id, other commands use table-id (not
2937 * just a name, they are different indexes). Would like to change this
2938 * to table-id for consistency.
2939 *
2940 * @cliexpar
2941 * Example of how to run the test lookup command:
2942 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2943 * No errors in 2 lookups
2944 * @cliexend
2945?*/
2946/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002947VLIB_CLI_COMMAND (lookup_test_command, static) =
2948{
2949 .path = "test lookup",
2950 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2951 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002952};
Billy McFall0683c9c2016-10-13 08:27:31 -04002953/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002954
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002955#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002956int
2957vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002958{
Neale Ranns107e7d42017-04-11 09:55:19 -07002959 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002960
Neale Ranns107e7d42017-04-11 09:55:19 -07002961 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2962
2963 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002964 return VNET_API_ERROR_NO_SUCH_FIB;
2965
Neale Ranns227038a2017-04-21 01:07:59 -07002966 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2967 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002968
Ed Warnickecb9cada2015-12-08 15:45:58 -07002969 return 0;
2970}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002971#endif
Dave Barach75fc8542016-10-11 16:16:02 -04002972
Ed Warnickecb9cada2015-12-08 15:45:58 -07002973static clib_error_t *
2974set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002975 unformat_input_t * input,
2976 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002977{
2978 int matched = 0;
2979 u32 table_id = 0;
2980 u32 flow_hash_config = 0;
2981 int rv;
2982
Dave Barachd7cb1b52016-12-09 09:52:16 -05002983 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2984 {
2985 if (unformat (input, "table %d", &table_id))
2986 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002987#define _(a,v) \
2988 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002989 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002990#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002991 else
2992 break;
2993 }
Dave Barach75fc8542016-10-11 16:16:02 -04002994
Ed Warnickecb9cada2015-12-08 15:45:58 -07002995 if (matched == 0)
2996 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002997 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002998
Ed Warnickecb9cada2015-12-08 15:45:58 -07002999 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
3000 switch (rv)
3001 {
3002 case 0:
3003 break;
Dave Barach75fc8542016-10-11 16:16:02 -04003004
Ed Warnickecb9cada2015-12-08 15:45:58 -07003005 case VNET_API_ERROR_NO_SUCH_FIB:
3006 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04003007
Ed Warnickecb9cada2015-12-08 15:45:58 -07003008 default:
3009 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3010 break;
3011 }
Dave Barach75fc8542016-10-11 16:16:02 -04003012
Ed Warnickecb9cada2015-12-08 15:45:58 -07003013 return 0;
3014}
Dave Barach75fc8542016-10-11 16:16:02 -04003015
Billy McFall0683c9c2016-10-13 08:27:31 -04003016/*?
3017 * Configure the set of IPv4 fields used by the flow hash.
3018 *
3019 * @cliexpar
3020 * Example of how to set the flow hash on a given table:
3021 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
3022 * Example of display the configured flow hash:
3023 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04003024 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3025 * 0.0.0.0/0
3026 * unicast-ip4-chain
3027 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
3028 * [0] [@0]: dpo-drop ip6
3029 * 0.0.0.0/32
3030 * unicast-ip4-chain
3031 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
3032 * [0] [@0]: dpo-drop ip6
3033 * 224.0.0.0/8
3034 * unicast-ip4-chain
3035 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
3036 * [0] [@0]: dpo-drop ip6
3037 * 6.0.1.2/32
3038 * unicast-ip4-chain
3039 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
3040 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3041 * 7.0.0.1/32
3042 * unicast-ip4-chain
3043 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
3044 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3045 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3046 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
3047 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
3048 * 240.0.0.0/8
3049 * unicast-ip4-chain
3050 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
3051 * [0] [@0]: dpo-drop ip6
3052 * 255.255.255.255/32
3053 * unicast-ip4-chain
3054 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
3055 * [0] [@0]: dpo-drop ip6
3056 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
3057 * 0.0.0.0/0
3058 * unicast-ip4-chain
3059 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
3060 * [0] [@0]: dpo-drop ip6
3061 * 0.0.0.0/32
3062 * unicast-ip4-chain
3063 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
3064 * [0] [@0]: dpo-drop ip6
3065 * 172.16.1.0/24
3066 * unicast-ip4-chain
3067 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
3068 * [0] [@4]: ipv4-glean: af_packet0
3069 * 172.16.1.1/32
3070 * unicast-ip4-chain
3071 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
3072 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
3073 * 172.16.1.2/32
3074 * unicast-ip4-chain
3075 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3076 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
3077 * 172.16.2.0/24
3078 * unicast-ip4-chain
3079 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
3080 * [0] [@4]: ipv4-glean: af_packet1
3081 * 172.16.2.1/32
3082 * unicast-ip4-chain
3083 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
3084 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
3085 * 224.0.0.0/8
3086 * unicast-ip4-chain
3087 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
3088 * [0] [@0]: dpo-drop ip6
3089 * 240.0.0.0/8
3090 * unicast-ip4-chain
3091 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
3092 * [0] [@0]: dpo-drop ip6
3093 * 255.255.255.255/32
3094 * unicast-ip4-chain
3095 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
3096 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04003097 * @cliexend
3098?*/
3099/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003100VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
3101{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003102 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04003103 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003104 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105 .function = set_ip_flow_hash_command_fn,
3106};
Billy McFall0683c9c2016-10-13 08:27:31 -04003107/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04003108
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003109#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05003110int
3111vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3112 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113{
Dave Barachd7cb1b52016-12-09 09:52:16 -05003114 vnet_main_t *vnm = vnet_get_main ();
3115 vnet_interface_main_t *im = &vnm->interface_main;
3116 ip4_main_t *ipm = &ip4_main;
3117 ip_lookup_main_t *lm = &ipm->lookup_main;
3118 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01003119 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003120
3121 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3122 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3123
3124 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3125 return VNET_API_ERROR_NO_SUCH_ENTRY;
3126
3127 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05003128 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003129
Neale Rannsdf089a82016-10-02 16:39:06 +01003130 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
3131
3132 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05003133 {
Neale Rannsdf089a82016-10-02 16:39:06 +01003134 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05003135 .fp_len = 32,
3136 .fp_proto = FIB_PROTOCOL_IP4,
3137 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01003138 };
3139 u32 fib_index;
3140
Dave Barachd7cb1b52016-12-09 09:52:16 -05003141 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3142 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01003143
3144
Dave Barachd7cb1b52016-12-09 09:52:16 -05003145 if (table_index != (u32) ~ 0)
3146 {
3147 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01003148
Dave Barachd7cb1b52016-12-09 09:52:16 -05003149 dpo_set (&dpo,
3150 DPO_CLASSIFY,
3151 DPO_PROTO_IP4,
3152 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01003153
Dave Barachd7cb1b52016-12-09 09:52:16 -05003154 fib_table_entry_special_dpo_add (fib_index,
3155 &pfx,
3156 FIB_SOURCE_CLASSIFY,
3157 FIB_ENTRY_FLAG_NONE, &dpo);
3158 dpo_reset (&dpo);
3159 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003160 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05003161 {
3162 fib_table_entry_special_remove (fib_index,
3163 &pfx, FIB_SOURCE_CLASSIFY);
3164 }
3165 }
Neale Rannsdf089a82016-10-02 16:39:06 +01003166
Ed Warnickecb9cada2015-12-08 15:45:58 -07003167 return 0;
3168}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02003169#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07003170
3171static clib_error_t *
3172set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05003173 unformat_input_t * input,
3174 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003175{
3176 u32 table_index = ~0;
3177 int table_index_set = 0;
3178 u32 sw_if_index = ~0;
3179 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04003180
Dave Barachd7cb1b52016-12-09 09:52:16 -05003181 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3182 {
3183 if (unformat (input, "table-index %d", &table_index))
3184 table_index_set = 1;
3185 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3186 vnet_get_main (), &sw_if_index))
3187 ;
3188 else
3189 break;
3190 }
Dave Barach75fc8542016-10-11 16:16:02 -04003191
Ed Warnickecb9cada2015-12-08 15:45:58 -07003192 if (table_index_set == 0)
3193 return clib_error_return (0, "classify table-index must be specified");
3194
3195 if (sw_if_index == ~0)
3196 return clib_error_return (0, "interface / subif must be specified");
3197
3198 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
3199
3200 switch (rv)
3201 {
3202 case 0:
3203 break;
3204
3205 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3206 return clib_error_return (0, "No such interface");
3207
3208 case VNET_API_ERROR_NO_SUCH_ENTRY:
3209 return clib_error_return (0, "No such classifier table");
3210 }
3211 return 0;
3212}
3213
Billy McFall0683c9c2016-10-13 08:27:31 -04003214/*?
3215 * Assign a classification table to an interface. The classification
3216 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3217 * commands. Once the table is create, use this command to filter packets
3218 * on an interface.
3219 *
3220 * @cliexpar
3221 * Example of how to assign a classification table to an interface:
3222 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
3223?*/
3224/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003225VLIB_CLI_COMMAND (set_ip_classify_command, static) =
3226{
Ed Warnickecb9cada2015-12-08 15:45:58 -07003227 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04003228 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04003229 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003230 .function = set_ip_classify_command_fn,
3231};
Billy McFall0683c9c2016-10-13 08:27:31 -04003232/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003233
Neale Ranns1ec36522017-11-29 05:20:37 -08003234static clib_error_t *
3235ip4_config (vlib_main_t * vm, unformat_input_t * input)
3236{
3237 ip4_main_t *im = &ip4_main;
3238 uword heapsize = 0;
3239
3240 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3241 {
3242 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3243 ;
3244 else
3245 return clib_error_return (0,
3246 "invalid heap-size parameter `%U'",
3247 format_unformat_error, input);
3248 }
3249
3250 im->mtrie_heap_size = heapsize;
3251
3252 return 0;
3253}
3254
3255VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3256
Dave Barachd7cb1b52016-12-09 09:52:16 -05003257/*
3258 * fd.io coding-style-patch-verification: ON
3259 *
3260 * Local Variables:
3261 * eval: (c-set-style "gnu")
3262 * End:
3263 */