blob: 40ae51ccd3bb496ed999b7d77c62a86ca9817875 [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>
Neale Rannsba4a5bf2020-01-09 06:43:14 +000059#include <vnet/classify/vnet_classify.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070060
Chris Luke8e5b0412016-07-26 13:06:10 -040061/** @brief IPv4 lookup node.
Dave Barach9770e202016-07-06 10:29:27 -040062 @node ip4-lookup
63
64 This is the main IPv4 lookup dispatch node.
65
66 @param vm vlib_main_t corresponding to the current thread
67 @param node vlib_node_runtime_t
68 @param frame vlib_frame_t whose contents should be dispatched
69
70 @par Graph mechanics: buffer metadata, next index usage
71
72 @em Uses:
73 - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
74 - Indicates the @c sw_if_index value of the interface that the
75 packet was received on.
76 - <code>vnet_buffer(b)->sw_if_index[VLIB_TX]</code>
77 - When the value is @c ~0 then the node performs a longest prefix
78 match (LPM) for the packet destination address in the FIB attached
79 to the receive interface.
80 - Otherwise perform LPM for the packet destination address in the
81 indicated FIB. In this case <code>[VLIB_TX]</code> is a FIB index
82 value (0, 1, ...) and not a VRF id.
83
84 @em Sets:
85 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
86 - The lookup result adjacency index.
87
88 <em>Next Index:</em>
89 - Dispatches the packet to the node index found in
90 ip_adjacency_t @c adj->lookup_next_index
91 (where @c adj is the lookup result adjacency).
92*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +020093VLIB_NODE_FN (ip4_lookup_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
94 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070095{
Neale Rannscb54e3c2019-06-19 07:14:10 +000096 return ip4_lookup_inline (vm, node, frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097}
98
Dave Barachd7cb1b52016-12-09 09:52:16 -050099static u8 *format_ip4_lookup_trace (u8 * s, va_list * args);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100100
Neale Rannsf8686322017-11-29 02:39:53 -0800101/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500102VLIB_REGISTER_NODE (ip4_lookup_node) =
103{
Neale Rannsf8686322017-11-29 02:39:53 -0800104 .name = "ip4-lookup",
105 .vector_size = sizeof (u32),
106 .format_trace = format_ip4_lookup_trace,
107 .n_next_nodes = IP_LOOKUP_N_NEXT,
108 .next_nodes = IP4_LOOKUP_NEXT_NODES,
109};
110/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100111
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200112VLIB_NODE_FN (ip4_load_balance_node) (vlib_main_t * vm,
113 vlib_node_runtime_t * node,
114 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500116 vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400117 u32 n_left, *from;
Damjan Marion067cd622018-07-11 12:47:43 +0200118 u32 thread_index = vm->thread_index;
Zhiyong Yang6fec8ea2019-05-05 22:52:43 +0800119 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
Neale Ranns3ce72b22019-05-27 08:21:32 -0400120 u16 nexts[VLIB_FRAME_SIZE], *next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100122 from = vlib_frame_vector_args (frame);
Neale Ranns3ce72b22019-05-27 08:21:32 -0400123 n_left = frame->n_vectors;
124 next = nexts;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100125
Neale Ranns3ce72b22019-05-27 08:21:32 -0400126 vlib_get_buffers (vm, from, bufs, n_left);
127
128 while (n_left >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400130 const load_balance_t *lb0, *lb1;
131 const ip4_header_t *ip0, *ip1;
132 u32 lbi0, hc0, lbi1, hc1;
133 const dpo_id_t *dpo0, *dpo1;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100134
Neale Ranns3ce72b22019-05-27 08:21:32 -0400135 /* Prefetch next iteration. */
136 {
137 vlib_prefetch_buffer_header (b[2], LOAD);
138 vlib_prefetch_buffer_header (b[3], LOAD);
139
140 CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), LOAD);
141 CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), LOAD);
142 }
143
144 ip0 = vlib_buffer_get_current (b[0]);
145 ip1 = vlib_buffer_get_current (b[1]);
146 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
147 lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
148
149 lb0 = load_balance_get (lbi0);
150 lb1 = load_balance_get (lbi1);
151
152 /*
153 * this node is for via FIBs we can re-use the hash value from the
154 * to node if present.
155 * We don't want to use the same hash value at each level in the recursion
156 * graph as that would lead to polarisation
157 */
158 hc0 = hc1 = 0;
159
160 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500161 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400162 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500163 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400164 hc0 = vnet_buffer (b[0])->ip.flow_hash =
165 vnet_buffer (b[0])->ip.flow_hash >> 1;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700166 }
167 else
168 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400169 hc0 = vnet_buffer (b[0])->ip.flow_hash =
170 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500171 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400172 dpo0 = load_balance_get_fwd_bucket
173 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
174 }
175 else
176 {
177 dpo0 = load_balance_get_bucket_i (lb0, 0);
178 }
179 if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
180 {
181 if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500182 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400183 hc1 = vnet_buffer (b[1])->ip.flow_hash =
184 vnet_buffer (b[1])->ip.flow_hash >> 1;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500185 }
Neale Rannsf12a83f2017-04-18 09:09:40 -0700186 else
187 {
Neale Ranns3ce72b22019-05-27 08:21:32 -0400188 hc1 = vnet_buffer (b[1])->ip.flow_hash =
189 ip4_compute_flow_hash (ip1, lb1->lb_hash_config);
Neale Rannsf12a83f2017-04-18 09:09:40 -0700190 }
Neale Ranns3ce72b22019-05-27 08:21:32 -0400191 dpo1 = load_balance_get_fwd_bucket
192 (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
193 }
194 else
195 {
196 dpo1 = load_balance_get_bucket_i (lb1, 0);
Dave Barachd7cb1b52016-12-09 09:52:16 -0500197 }
Neale Ranns2be95c12016-11-19 13:50:04 +0000198
Neale Ranns3ce72b22019-05-27 08:21:32 -0400199 next[0] = dpo0->dpoi_next_node;
200 next[1] = dpo1->dpoi_next_node;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100201
Neale Ranns3ce72b22019-05-27 08:21:32 -0400202 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
203 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100204
Neale Ranns3ce72b22019-05-27 08:21:32 -0400205 vlib_increment_combined_counter
206 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
207 vlib_increment_combined_counter
208 (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100209
Neale Ranns3ce72b22019-05-27 08:21:32 -0400210 b += 2;
211 next += 2;
212 n_left -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 }
214
Neale Ranns3ce72b22019-05-27 08:21:32 -0400215 while (n_left > 0)
216 {
217 const load_balance_t *lb0;
218 const ip4_header_t *ip0;
219 const dpo_id_t *dpo0;
220 u32 lbi0, hc0;
221
222 ip0 = vlib_buffer_get_current (b[0]);
223 lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
224
225 lb0 = load_balance_get (lbi0);
226
227 hc0 = 0;
228 if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
229 {
230 if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
231 {
232 hc0 = vnet_buffer (b[0])->ip.flow_hash =
233 vnet_buffer (b[0])->ip.flow_hash >> 1;
234 }
235 else
236 {
237 hc0 = vnet_buffer (b[0])->ip.flow_hash =
238 ip4_compute_flow_hash (ip0, lb0->lb_hash_config);
239 }
240 dpo0 = load_balance_get_fwd_bucket
241 (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
242 }
243 else
244 {
245 dpo0 = load_balance_get_bucket_i (lb0, 0);
246 }
247
248 next[0] = dpo0->dpoi_next_node;
249 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
250
251 vlib_increment_combined_counter
252 (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
253
254 b += 1;
255 next += 1;
256 n_left -= 1;
257 }
258
259 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Neale Rannsa71844f2018-11-08 07:31:36 -0800260 if (node->flags & VLIB_NODE_FLAG_TRACE)
261 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
262
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100263 return frame->n_vectors;
264}
265
Neale Rannsf8686322017-11-29 02:39:53 -0800266/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500267VLIB_REGISTER_NODE (ip4_load_balance_node) =
268{
Neale Rannsf8686322017-11-29 02:39:53 -0800269 .name = "ip4-load-balance",
270 .vector_size = sizeof (u32),
271 .sibling_of = "ip4-lookup",
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200272 .format_trace = format_ip4_lookup_trace,
Neale Rannsf8686322017-11-29 02:39:53 -0800273};
274/* *INDENT-ON* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100275
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200276#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100277/* get first interface address */
278ip4_address_t *
279ip4_interface_first_address (ip4_main_t * im, u32 sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500280 ip_interface_address_t ** result_ia)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100281{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500282 ip_lookup_main_t *lm = &im->lookup_main;
283 ip_interface_address_t *ia = 0;
284 ip4_address_t *result = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100285
Neale Ranns32e1c012016-11-22 17:07:28 +0000286 /* *INDENT-OFF* */
287 foreach_ip_interface_address
288 (lm, ia, sw_if_index,
289 1 /* honor unnumbered */ ,
290 ({
291 ip4_address_t * a =
292 ip_interface_address_get_address (lm, ia);
293 result = a;
294 break;
295 }));
296 /* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 if (result_ia)
298 *result_ia = result ? ia : 0;
299 return result;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300}
Matthew G Smith88d29a92019-07-17 10:01:17 -0500301#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
303static void
Neale Ranns1855b8e2018-07-11 10:31:26 -0700304ip4_add_subnet_bcast_route (u32 fib_index,
305 fib_prefix_t *pfx,
306 u32 sw_if_index)
307{
308 vnet_sw_interface_flags_t iflags;
309
310 iflags = vnet_sw_interface_get_flags(vnet_get_main(), sw_if_index);
311
312 fib_table_entry_special_remove(fib_index,
313 pfx,
314 FIB_SOURCE_INTERFACE);
315
316 if (iflags & VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST)
317 {
318 fib_table_entry_update_one_path (fib_index, pfx,
319 FIB_SOURCE_INTERFACE,
320 FIB_ENTRY_FLAG_NONE,
321 DPO_PROTO_IP4,
322 /* No next-hop address */
323 &ADJ_BCAST_ADDR,
324 sw_if_index,
325 // invalid FIB index
326 ~0,
327 1,
328 // no out-label stack
329 NULL,
330 FIB_ROUTE_PATH_FLAG_NONE);
331 }
332 else
333 {
334 fib_table_entry_special_add(fib_index,
335 pfx,
336 FIB_SOURCE_INTERFACE,
337 (FIB_ENTRY_FLAG_DROP |
338 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
339 }
340}
341
342static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500343ip4_add_interface_prefix_routes (ip4_main_t *im,
344 u32 sw_if_index,
345 u32 fib_index,
346 ip_interface_address_t * a)
347{
348 ip_lookup_main_t *lm = &im->lookup_main;
349 ip_interface_prefix_t *if_prefix;
350 ip4_address_t *address = ip_interface_address_get_address (lm, a);
351
352 ip_interface_prefix_key_t key = {
353 .prefix = {
354 .fp_len = a->address_length,
355 .fp_proto = FIB_PROTOCOL_IP4,
356 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
357 },
358 .sw_if_index = sw_if_index,
359 };
360
361 fib_prefix_t pfx_special = {
362 .fp_proto = FIB_PROTOCOL_IP4,
363 };
364
365 /* If prefix already set on interface, just increment ref count & return */
366 if_prefix = ip_get_interface_prefix (lm, &key);
367 if (if_prefix)
368 {
369 if_prefix->ref_count += 1;
370 return;
371 }
372
373 /* New prefix - allocate a pool entry, initialize it, add to the hash */
374 pool_get (lm->if_prefix_pool, if_prefix);
375 if_prefix->ref_count = 1;
376 if_prefix->src_ia_index = a - lm->if_address_pool;
377 clib_memcpy (&if_prefix->key, &key, sizeof (key));
378 mhash_set (&lm->prefix_to_if_prefix_index, &key,
379 if_prefix - lm->if_prefix_pool, 0 /* old value */);
380
381 /* length <= 30 - add glean, drop first address, maybe drop bcast address */
382 if (a->address_length <= 30)
383 {
384 pfx_special.fp_len = a->address_length;
385 pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
386
387 /* set the glean route for the prefix */
388 fib_table_entry_update_one_path (fib_index, &pfx_special,
389 FIB_SOURCE_INTERFACE,
390 (FIB_ENTRY_FLAG_CONNECTED |
391 FIB_ENTRY_FLAG_ATTACHED),
392 DPO_PROTO_IP4,
393 /* No next-hop address */
394 NULL,
395 sw_if_index,
396 /* invalid FIB index */
397 ~0,
398 1,
399 /* no out-label stack */
400 NULL,
401 FIB_ROUTE_PATH_FLAG_NONE);
402
403 /* set a drop route for the base address of the prefix */
404 pfx_special.fp_len = 32;
405 pfx_special.fp_addr.ip4.as_u32 =
406 address->as_u32 & im->fib_masks[a->address_length];
407
408 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
409 fib_table_entry_special_add (fib_index, &pfx_special,
410 FIB_SOURCE_INTERFACE,
411 (FIB_ENTRY_FLAG_DROP |
412 FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
413
414 /* set a route for the broadcast address of the prefix */
415 pfx_special.fp_len = 32;
416 pfx_special.fp_addr.ip4.as_u32 =
417 address->as_u32 | ~im->fib_masks[a->address_length];
418 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
419 ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
420
421
422 }
423 /* length == 31 - add an attached route for the other address */
424 else if (a->address_length == 31)
425 {
426 pfx_special.fp_len = 32;
427 pfx_special.fp_addr.ip4.as_u32 =
428 address->as_u32 ^ clib_host_to_net_u32(1);
429
430 fib_table_entry_update_one_path (fib_index, &pfx_special,
431 FIB_SOURCE_INTERFACE,
432 (FIB_ENTRY_FLAG_ATTACHED),
433 DPO_PROTO_IP4,
434 &pfx_special.fp_addr,
435 sw_if_index,
436 /* invalid FIB index */
437 ~0,
438 1,
439 NULL,
440 FIB_ROUTE_PATH_FLAG_NONE);
441 }
442}
443
444static void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445ip4_add_interface_routes (u32 sw_if_index,
446 ip4_main_t * im, u32 fib_index,
447 ip_interface_address_t * a)
448{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500449 ip_lookup_main_t *lm = &im->lookup_main;
450 ip4_address_t *address = ip_interface_address_get_address (lm, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100451 fib_prefix_t pfx = {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500452 .fp_len = 32,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500453 .fp_proto = FIB_PROTOCOL_IP4,
454 .fp_addr.ip4 = *address,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100455 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500457 /* set special routes for the prefix if needed */
458 ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100459
460 if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
Dave Barachd7cb1b52016-12-09 09:52:16 -0500461 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100462 u32 classify_table_index =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500463 lm->classify_table_index_by_sw_if_index[sw_if_index];
464 if (classify_table_index != (u32) ~ 0)
465 {
466 dpo_id_t dpo = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100467
Dave Barachd7cb1b52016-12-09 09:52:16 -0500468 dpo_set (&dpo,
469 DPO_CLASSIFY,
470 DPO_PROTO_IP4,
471 classify_dpo_create (DPO_PROTO_IP4, classify_table_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100472
Dave Barachd7cb1b52016-12-09 09:52:16 -0500473 fib_table_entry_special_dpo_add (fib_index,
474 &pfx,
475 FIB_SOURCE_CLASSIFY,
476 FIB_ENTRY_FLAG_NONE, &dpo);
477 dpo_reset (&dpo);
478 }
479 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100480
Neale Ranns32e1c012016-11-22 17:07:28 +0000481 fib_table_entry_update_one_path (fib_index, &pfx,
482 FIB_SOURCE_INTERFACE,
483 (FIB_ENTRY_FLAG_CONNECTED |
484 FIB_ENTRY_FLAG_LOCAL),
Neale Rannsda78f952017-05-24 09:15:43 -0700485 DPO_PROTO_IP4,
Neale Ranns32e1c012016-11-22 17:07:28 +0000486 &pfx.fp_addr,
487 sw_if_index,
488 // invalid FIB index
489 ~0,
490 1, NULL,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500491 FIB_ROUTE_PATH_FLAG_NONE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492}
493
494static void
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500495ip4_del_interface_prefix_routes (ip4_main_t * im,
496 u32 sw_if_index,
497 u32 fib_index,
498 ip4_address_t * address,
499 u32 address_length)
500{
501 ip_lookup_main_t *lm = &im->lookup_main;
502 ip_interface_prefix_t *if_prefix;
503
504 ip_interface_prefix_key_t key = {
505 .prefix = {
506 .fp_len = address_length,
507 .fp_proto = FIB_PROTOCOL_IP4,
508 .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
509 },
510 .sw_if_index = sw_if_index,
511 };
512
513 fib_prefix_t pfx_special = {
514 .fp_len = 32,
515 .fp_proto = FIB_PROTOCOL_IP4,
516 };
517
518 if_prefix = ip_get_interface_prefix (lm, &key);
519 if (!if_prefix)
520 {
521 clib_warning ("Prefix not found while deleting %U",
522 format_ip4_address_and_length, address, address_length);
523 return;
524 }
525
526 if_prefix->ref_count -= 1;
527
528 /*
529 * Routes need to be adjusted if:
530 * - deleting last intf addr in prefix
531 * - deleting intf addr used as default source address in glean adjacency
532 *
533 * We're done now otherwise
534 */
535 if ((if_prefix->ref_count > 0) &&
536 !pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
537 return;
538
539 /* length <= 30, delete glean route, first address, last address */
540 if (address_length <= 30)
541 {
542
543 /* remove glean route for prefix */
544 pfx_special.fp_addr.ip4 = *address;
545 pfx_special.fp_len = address_length;
546 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
547
548 /* if no more intf addresses in prefix, remove other special routes */
549 if (!if_prefix->ref_count)
550 {
551 /* first address in prefix */
552 pfx_special.fp_addr.ip4.as_u32 =
553 address->as_u32 & im->fib_masks[address_length];
554 pfx_special.fp_len = 32;
555
556 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
557 fib_table_entry_special_remove (fib_index,
558 &pfx_special,
559 FIB_SOURCE_INTERFACE);
560
561 /* prefix broadcast address */
562 pfx_special.fp_addr.ip4.as_u32 =
563 address->as_u32 | ~im->fib_masks[address_length];
564 pfx_special.fp_len = 32;
565
566 if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
567 fib_table_entry_special_remove (fib_index,
568 &pfx_special,
569 FIB_SOURCE_INTERFACE);
570 }
571 else
572 /* default source addr just got deleted, find another */
573 {
574 ip_interface_address_t *new_src_ia = NULL;
575 ip4_address_t *new_src_addr = NULL;
576
577 new_src_addr =
578 ip4_interface_address_matching_destination
579 (im, address, sw_if_index, &new_src_ia);
580
581 if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
582
583 pfx_special.fp_len = address_length;
584 pfx_special.fp_addr.ip4 = *new_src_addr;
585
586 /* set new glean route for the prefix */
587 fib_table_entry_update_one_path (fib_index, &pfx_special,
588 FIB_SOURCE_INTERFACE,
589 (FIB_ENTRY_FLAG_CONNECTED |
590 FIB_ENTRY_FLAG_ATTACHED),
591 DPO_PROTO_IP4,
592 /* No next-hop address */
593 NULL,
594 sw_if_index,
595 /* invalid FIB index */
596 ~0,
597 1,
598 /* no out-label stack */
599 NULL,
600 FIB_ROUTE_PATH_FLAG_NONE);
601 return;
602 }
603 }
604 /* length == 31, delete attached route for the other address */
605 else if (address_length == 31)
606 {
607 pfx_special.fp_addr.ip4.as_u32 =
608 address->as_u32 ^ clib_host_to_net_u32(1);
609
610 fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
611 }
612
613 mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
614 pool_put (lm->if_prefix_pool, if_prefix);
615}
616
617static void
618ip4_del_interface_routes (u32 sw_if_index,
619 ip4_main_t * im,
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100620 u32 fib_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500621 ip4_address_t * address, u32 address_length)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500623 fib_prefix_t pfx = {
624 .fp_len = address_length,
625 .fp_proto = FIB_PROTOCOL_IP4,
626 .fp_addr.ip4 = *address,
627 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500629 ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
630 address, address_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631
Dave Barachd7cb1b52016-12-09 09:52:16 -0500632 pfx.fp_len = 32;
633 fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634}
635
Matthew G Smith88d29a92019-07-17 10:01:17 -0500636#ifndef CLIB_MARCH_VARIANT
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100637void
Dave Barachd7cb1b52016-12-09 09:52:16 -0500638ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100639{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500640 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700641
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642 vec_validate_init_empty (im->ip_enabled_by_sw_if_index, sw_if_index, 0);
643
644 /*
645 * enable/disable only on the 1<->0 transition
646 */
647 if (is_enable)
648 {
649 if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500650 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100651 }
652 else
653 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500654 ASSERT (im->ip_enabled_by_sw_if_index[sw_if_index] > 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100655 if (0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
Dave Barachd7cb1b52016-12-09 09:52:16 -0500656 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100657 }
Neale Ranns8269d3d2018-01-30 09:02:20 -0800658 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion4d489932016-12-09 03:21:27 -0800659 !is_enable, 0, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100660
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100661
Neale Ranns8269d3d2018-01-30 09:02:20 -0800662 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400663 sw_if_index, !is_enable, 0, 0);
Neale Ranns57e53bb2019-05-29 13:58:43 +0000664
665 {
666 ip4_enable_disable_interface_callback_t *cb;
667 vec_foreach (cb, im->enable_disable_interface_callbacks)
668 cb->function (im, cb->function_opaque, sw_if_index, is_enable);
669 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100670}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672static clib_error_t *
673ip4_add_del_interface_address_internal (vlib_main_t * vm,
674 u32 sw_if_index,
675 ip4_address_t * address,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500676 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500678 vnet_main_t *vnm = vnet_get_main ();
679 ip4_main_t *im = &ip4_main;
680 ip_lookup_main_t *lm = &im->lookup_main;
681 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682 u32 if_address_index, elts_before;
Dave Barachd7cb1b52016-12-09 09:52:16 -0500683 ip4_address_fib_t ip4_af, *addr_fib = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684
Pavel Kotucek57808982017-08-02 08:20:19 +0200685 /* local0 interface doesn't support IP addressing */
686 if (sw_if_index == 0)
687 {
688 return
689 clib_error_create ("local0 interface doesn't support IP addressing");
690 }
691
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
693 ip4_addr_fib_init (&ip4_af, address,
694 vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
695 vec_add1 (addr_fib, ip4_af);
696
Neale Ranns744902e2017-08-14 10:35:44 -0700697 /*
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100698 * there is no support for adj-fib handling in the presence of overlapping
699 * subnets on interfaces. Easy fix - disallow overlapping subnets, like
700 * most routers do.
701 */
Neale Ranns32e1c012016-11-22 17:07:28 +0000702 /* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500703 if (!is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100705 /* When adding an address check that it does not conflict
Neale Ranns744902e2017-08-14 10:35:44 -0700706 with an existing address on any interface in this table. */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500707 ip_interface_address_t *ia;
Neale Ranns744902e2017-08-14 10:35:44 -0700708 vnet_sw_interface_t *sif;
709
710 pool_foreach(sif, vnm->interface_main.sw_interfaces,
711 ({
712 if (im->fib_index_by_sw_if_index[sw_if_index] ==
713 im->fib_index_by_sw_if_index[sif->sw_if_index])
714 {
715 foreach_ip_interface_address
716 (&im->lookup_main, ia, sif->sw_if_index,
717 0 /* honor unnumbered */ ,
718 ({
719 ip4_address_t * x =
720 ip_interface_address_get_address
721 (&im->lookup_main, ia);
722 if (ip4_destination_matches_route
723 (im, address, x, ia->address_length) ||
724 ip4_destination_matches_route (im,
725 x,
726 address,
727 address_length))
728 {
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500729 /* an intf may have >1 addr from the same prefix */
730 if ((sw_if_index == sif->sw_if_index) &&
731 (ia->address_length == address_length) &&
732 (x->as_u32 != address->as_u32))
733 continue;
734
735 /* error if the length or intf was different */
Neale Ranns744902e2017-08-14 10:35:44 -0700736 vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
737
738 return
739 clib_error_create
Ole Troan33a58172019-09-04 09:12:29 +0200740 ("failed to add %U on %U which conflicts with %U for interface %U",
Neale Ranns744902e2017-08-14 10:35:44 -0700741 format_ip4_address_and_length, address,
742 address_length,
Ole Troan33a58172019-09-04 09:12:29 +0200743 format_vnet_sw_if_index_name, vnm,
744 sw_if_index,
Neale Ranns744902e2017-08-14 10:35:44 -0700745 format_ip4_address_and_length, x,
746 ia->address_length,
747 format_vnet_sw_if_index_name, vnm,
748 sif->sw_if_index);
749 }
750 }));
751 }
752 }));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700753 }
Neale Ranns32e1c012016-11-22 17:07:28 +0000754 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756 elts_before = pool_elts (lm->if_address_pool);
757
758 error = ip_interface_address_add_del
Dave Barachd7cb1b52016-12-09 09:52:16 -0500759 (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760 if (error)
761 goto done;
Dave Barach75fc8542016-10-11 16:16:02 -0400762
Dave Barachd7cb1b52016-12-09 09:52:16 -0500763 ip4_sw_interface_enable_disable (sw_if_index, !is_del);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100764
Matthew G Smith88d29a92019-07-17 10:01:17 -0500765 /* intf addr routes are added/deleted on admin up/down */
766 if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
767 {
768 if (is_del)
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500769 ip4_del_interface_routes (sw_if_index,
770 im, ip4_af.fib_index, address,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500771 address_length);
772 else
773 ip4_add_interface_routes (sw_if_index,
774 im, ip4_af.fib_index,
775 pool_elt_at_index
776 (lm->if_address_pool, if_address_index));
777 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778
779 /* If pool did not grow/shrink: add duplicate address. */
780 if (elts_before != pool_elts (lm->if_address_pool))
781 {
Dave Barachd7cb1b52016-12-09 09:52:16 -0500782 ip4_add_del_interface_address_callback_t *cb;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783 vec_foreach (cb, im->add_del_interface_address_callbacks)
784 cb->function (im, cb->function_opaque, sw_if_index,
Dave Barachd7cb1b52016-12-09 09:52:16 -0500785 address, address_length, if_address_index, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 }
787
Dave Barachd7cb1b52016-12-09 09:52:16 -0500788done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700789 vec_free (addr_fib);
790 return error;
791}
792
793clib_error_t *
Neale Ranns32e1c012016-11-22 17:07:28 +0000794ip4_add_del_interface_address (vlib_main_t * vm,
795 u32 sw_if_index,
796 ip4_address_t * address,
797 u32 address_length, u32 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798{
799 return ip4_add_del_interface_address_internal
Dave Barachd7cb1b52016-12-09 09:52:16 -0500800 (vm, sw_if_index, address, address_length, is_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801}
802
Neale Ranns1855b8e2018-07-11 10:31:26 -0700803void
804ip4_directed_broadcast (u32 sw_if_index, u8 enable)
805{
806 ip_interface_address_t *ia;
807 ip4_main_t *im;
808
809 im = &ip4_main;
810
811 /*
812 * when directed broadcast is enabled, the subnet braodcast route will forward
813 * packets using an adjacency with a broadcast MAC. otherwise it drops
814 */
815 /* *INDENT-OFF* */
816 foreach_ip_interface_address(&im->lookup_main, ia,
817 sw_if_index, 0,
818 ({
819 if (ia->address_length <= 30)
820 {
821 ip4_address_t *ipa;
822
823 ipa = ip_interface_address_get_address (&im->lookup_main, ia);
824
825 fib_prefix_t pfx = {
826 .fp_len = 32,
827 .fp_proto = FIB_PROTOCOL_IP4,
828 .fp_addr = {
829 .ip4.as_u32 = (ipa->as_u32 | ~im->fib_masks[ia->address_length]),
830 },
831 };
832
833 ip4_add_subnet_bcast_route
834 (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
835 sw_if_index),
836 &pfx, sw_if_index);
837 }
838 }));
839 /* *INDENT-ON* */
840}
Damjan Marionc9dad5d2018-08-11 22:10:29 +0200841#endif
Neale Ranns1855b8e2018-07-11 10:31:26 -0700842
Matthew G Smith88d29a92019-07-17 10:01:17 -0500843static clib_error_t *
844ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
845{
846 ip4_main_t *im = &ip4_main;
847 ip_interface_address_t *ia;
848 ip4_address_t *a;
849 u32 is_admin_up, fib_index;
850
851 /* Fill in lookup tables with default table (0). */
852 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
853
854 vec_validate_init_empty (im->
855 lookup_main.if_address_pool_index_by_sw_if_index,
856 sw_if_index, ~0);
857
858 is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
859
860 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
861
862 /* *INDENT-OFF* */
863 foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
864 0 /* honor unnumbered */,
865 ({
866 a = ip_interface_address_get_address (&im->lookup_main, ia);
867 if (is_admin_up)
868 ip4_add_interface_routes (sw_if_index,
869 im, fib_index,
870 ia);
871 else
Matthew Smith6c92f5b2019-08-07 11:46:30 -0500872 ip4_del_interface_routes (sw_if_index,
873 im, fib_index,
Matthew G Smith88d29a92019-07-17 10:01:17 -0500874 a, ia->address_length);
875 }));
876 /* *INDENT-ON* */
877
878 return 0;
879}
880
881VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip4_sw_interface_admin_up_down);
882
Dave Barachd6534602016-06-14 18:38:02 -0400883/* Built-in ip4 unicast rx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -0500884/* *INDENT-OFF* */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100885VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
886{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500887 .arc_name = "ip4-unicast",
Damjan Marion892e0762016-12-09 18:52:05 +0100888 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500889 .last_in_arc = "ip4-lookup",
Damjan Marion892e0762016-12-09 18:52:05 +0100890 .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
891};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100892
Dave Barachd7cb1b52016-12-09 09:52:16 -0500893VNET_FEATURE_INIT (ip4_flow_classify, static) =
894{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100895 .arc_name = "ip4-unicast",
Juraj Sloboda506b2452016-08-07 23:45:24 -0700896 .node_name = "ip4-flow-classify",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100897 .runs_before = VNET_FEATURES ("ip4-inacl"),
Juraj Sloboda506b2452016-08-07 23:45:24 -0700898};
899
Dave Barachd7cb1b52016-12-09 09:52:16 -0500900VNET_FEATURE_INIT (ip4_inacl, static) =
901{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100902 .arc_name = "ip4-unicast",
Dave Barach75fc8542016-10-11 16:16:02 -0400903 .node_name = "ip4-inacl",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100904 .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
Dave Barachd6534602016-06-14 18:38:02 -0400905};
906
Dave Barachd7cb1b52016-12-09 09:52:16 -0500907VNET_FEATURE_INIT (ip4_source_check_1, static) =
908{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100909 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400910 .node_name = "ip4-source-check-via-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100911 .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
Dave Barachd6534602016-06-14 18:38:02 -0400912};
913
Dave Barachd7cb1b52016-12-09 09:52:16 -0500914VNET_FEATURE_INIT (ip4_source_check_2, static) =
915{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100916 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400917 .node_name = "ip4-source-check-via-any",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100918 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barachd6534602016-06-14 18:38:02 -0400919};
920
Dave Barachd7cb1b52016-12-09 09:52:16 -0500921VNET_FEATURE_INIT (ip4_source_and_port_range_check_rx, static) =
922{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100923 .arc_name = "ip4-unicast",
Dave Barach5331c722016-08-17 11:54:30 -0400924 .node_name = "ip4-source-and-port-range-check-rx",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100925 .runs_before = VNET_FEATURES ("ip4-policer-classify"),
Dave Barach6f9bca22016-04-30 10:25:32 -0400926};
927
Dave Barachd7cb1b52016-12-09 09:52:16 -0500928VNET_FEATURE_INIT (ip4_policer_classify, static) =
929{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100930 .arc_name = "ip4-unicast",
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700931 .node_name = "ip4-policer-classify",
Pierre Pfister057b3562018-12-10 17:01:01 +0100932 .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
Matus Fabian70e6a8d2016-06-20 08:10:42 -0700933};
934
Dave Barachd7cb1b52016-12-09 09:52:16 -0500935VNET_FEATURE_INIT (ip4_ipsec, static) =
936{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100937 .arc_name = "ip4-unicast",
Pierre Pfister057b3562018-12-10 17:01:01 +0100938 .node_name = "ipsec4-input-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100939 .runs_before = VNET_FEATURES ("vpath-input-ip4"),
Dave Barachd6534602016-06-14 18:38:02 -0400940};
941
Dave Barachd7cb1b52016-12-09 09:52:16 -0500942VNET_FEATURE_INIT (ip4_vpath, static) =
943{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100944 .arc_name = "ip4-unicast",
Dave Barachd6534602016-06-14 18:38:02 -0400945 .node_name = "vpath-input-ip4",
John Lo37682e12016-11-30 12:51:39 -0500946 .runs_before = VNET_FEATURES ("ip4-vxlan-bypass"),
947};
948
Dave Barachd7cb1b52016-12-09 09:52:16 -0500949VNET_FEATURE_INIT (ip4_vxlan_bypass, static) =
950{
John Lo37682e12016-11-30 12:51:39 -0500951 .arc_name = "ip4-unicast",
952 .node_name = "ip4-vxlan-bypass",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100953 .runs_before = VNET_FEATURES ("ip4-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400954};
955
Neale Ranns8269d3d2018-01-30 09:02:20 -0800956VNET_FEATURE_INIT (ip4_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500957{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100958 .arc_name = "ip4-unicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800959 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400960 .runs_before = VNET_FEATURES ("ip4-lookup"),
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100961};
962
Neale Ranns180279b2017-03-16 15:49:09 -0400963VNET_FEATURE_INIT (ip4_lookup, static) =
964{
965 .arc_name = "ip4-unicast",
966 .node_name = "ip4-lookup",
967 .runs_before = 0, /* not before any other features */
968};
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100969
Dave Barachd6534602016-06-14 18:38:02 -0400970/* Built-in ip4 multicast rx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +0100971VNET_FEATURE_ARC_INIT (ip4_multicast, static) =
972{
Dave Barachd7cb1b52016-12-09 09:52:16 -0500973 .arc_name = "ip4-multicast",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100974 .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
Dave Baracha25def72018-11-26 11:04:45 -0500975 .last_in_arc = "ip4-mfib-forward-lookup",
Damjan Marion8b3191e2016-11-09 19:54:20 +0100976 .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index,
977};
978
Dave Barachd7cb1b52016-12-09 09:52:16 -0500979VNET_FEATURE_INIT (ip4_vpath_mc, static) =
980{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100981 .arc_name = "ip4-multicast",
Dave Barachd6534602016-06-14 18:38:02 -0400982 .node_name = "vpath-input-ip4",
Neale Ranns32e1c012016-11-22 17:07:28 +0000983 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
Dave Barachd6534602016-06-14 18:38:02 -0400984};
985
Neale Ranns8269d3d2018-01-30 09:02:20 -0800986VNET_FEATURE_INIT (ip4_mc_not_enabled, static) =
Dave Barachd7cb1b52016-12-09 09:52:16 -0500987{
Damjan Marion8b3191e2016-11-09 19:54:20 +0100988 .arc_name = "ip4-multicast",
Neale Ranns8269d3d2018-01-30 09:02:20 -0800989 .node_name = "ip4-not-enabled",
Neale Ranns180279b2017-03-16 15:49:09 -0400990 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
991};
992
993VNET_FEATURE_INIT (ip4_lookup_mc, static) =
994{
995 .arc_name = "ip4-multicast",
996 .node_name = "ip4-mfib-forward-lookup",
Dave Barachd7cb1b52016-12-09 09:52:16 -0500997 .runs_before = 0, /* last feature */
Neale Ranns5e575b12016-10-03 09:40:25 +0100998};
Dave Barach5331c722016-08-17 11:54:30 -0400999
1000/* Source and port-range check ip4 tx feature path definition */
Damjan Marion8b3191e2016-11-09 19:54:20 +01001001VNET_FEATURE_ARC_INIT (ip4_output, static) =
1002{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001003 .arc_name = "ip4-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -08001004 .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain", "ip4-dvr-dpo"),
Dave Baracha25def72018-11-26 11:04:45 -05001005 .last_in_arc = "interface-output",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001006 .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index,
1007};
Dave Barach5331c722016-08-17 11:54:30 -04001008
Dave Barachd7cb1b52016-12-09 09:52:16 -05001009VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) =
1010{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001011 .arc_name = "ip4-output",
1012 .node_name = "ip4-source-and-port-range-check-tx",
Andrew Yourtchenko815d7d52018-02-07 11:37:02 +01001013 .runs_before = VNET_FEATURES ("ip4-outacl"),
1014};
1015
1016VNET_FEATURE_INIT (ip4_outacl, static) =
1017{
1018 .arc_name = "ip4-output",
1019 .node_name = "ip4-outacl",
Pierre Pfister057b3562018-12-10 17:01:01 +01001020 .runs_before = VNET_FEATURES ("ipsec4-output-feature"),
Matus Fabian08a6f012016-11-15 06:08:51 -08001021};
1022
Dave Barachd7cb1b52016-12-09 09:52:16 -05001023VNET_FEATURE_INIT (ip4_ipsec_output, static) =
1024{
Matus Fabian08a6f012016-11-15 06:08:51 -08001025 .arc_name = "ip4-output",
Pierre Pfister057b3562018-12-10 17:01:01 +01001026 .node_name = "ipsec4-output-feature",
Damjan Marion8b3191e2016-11-09 19:54:20 +01001027 .runs_before = VNET_FEATURES ("interface-output"),
Dave Barach5331c722016-08-17 11:54:30 -04001028};
1029
1030/* Built-in ip4 tx feature path definition */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001031VNET_FEATURE_INIT (ip4_interface_output, static) =
1032{
Damjan Marion8b3191e2016-11-09 19:54:20 +01001033 .arc_name = "ip4-output",
Dave Barach5331c722016-08-17 11:54:30 -04001034 .node_name = "interface-output",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001035 .runs_before = 0, /* not before any other features */
Dave Barach5331c722016-08-17 11:54:30 -04001036};
Dave Barachd7cb1b52016-12-09 09:52:16 -05001037/* *INDENT-ON* */
Dave Barachd6534602016-06-14 18:38:02 -04001038
Ed Warnickecb9cada2015-12-08 15:45:58 -07001039static clib_error_t *
Dave Barachd7cb1b52016-12-09 09:52:16 -05001040ip4_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001042 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001044 /* Fill in lookup tables with default table (0). */
1045 vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
Neale Ranns32e1c012016-11-22 17:07:28 +00001046 vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001047
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001048 if (!is_add)
1049 {
1050 ip4_main_t *im4 = &ip4_main;
1051 ip_lookup_main_t *lm4 = &im4->lookup_main;
1052 ip_interface_address_t *ia = 0;
1053 ip4_address_t *address;
1054 vlib_main_t *vm = vlib_get_main ();
1055
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001056 vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001057 /* *INDENT-OFF* */
Neale Ranns2ae2bc52018-03-16 03:22:39 -07001058 foreach_ip_interface_address (lm4, ia, sw_if_index, 0,
Pavel Kotucek9f5a2b62017-06-14 13:56:55 +02001059 ({
1060 address = ip_interface_address_get_address (lm4, ia);
1061 ip4_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
1062 }));
1063 /* *INDENT-ON* */
1064 }
1065
Neale Ranns8269d3d2018-01-30 09:02:20 -08001066 vnet_feature_enable_disable ("ip4-unicast", "ip4-not-enabled", sw_if_index,
Damjan Marion8b3191e2016-11-09 19:54:20 +01001067 is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068
Neale Ranns8269d3d2018-01-30 09:02:20 -08001069 vnet_feature_enable_disable ("ip4-multicast", "ip4-not-enabled",
1070 sw_if_index, is_add, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072 return /* no error */ 0;
1073}
1074
1075VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip4_sw_interface_add_del);
1076
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077/* Global IP4 main. */
Benoît Ganne47727c02019-02-12 13:35:08 +01001078#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079ip4_main_t ip4_main;
Benoît Ganne47727c02019-02-12 13:35:08 +01001080#endif /* CLIB_MARCH_VARIANT */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001081
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001082static clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083ip4_lookup_init (vlib_main_t * vm)
1084{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001085 ip4_main_t *im = &ip4_main;
1086 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001087 uword i;
1088
Damjan Marion8b3191e2016-11-09 19:54:20 +01001089 if ((error = vlib_call_init_function (vm, vnet_feature_init)))
1090 return error;
Neale Ranns1ec36522017-11-29 05:20:37 -08001091 if ((error = vlib_call_init_function (vm, ip4_mtrie_module_init)))
1092 return (error);
1093 if ((error = vlib_call_init_function (vm, fib_module_init)))
1094 return error;
1095 if ((error = vlib_call_init_function (vm, mfib_module_init)))
1096 return error;
Damjan Marion8b3191e2016-11-09 19:54:20 +01001097
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
1099 {
1100 u32 m;
1101
1102 if (i < 32)
1103 m = pow2_mask (i) << (32 - i);
Dave Barach75fc8542016-10-11 16:16:02 -04001104 else
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105 m = ~0;
1106 im->fib_masks[i] = clib_host_to_net_u32 (m);
1107 }
1108
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109 ip_lookup_init (&im->lookup_main, /* is_ip6 */ 0);
1110
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001111 /* Create FIB with index 0 and table id of 0. */
Neale Ranns15002542017-09-10 04:39:11 -07001112 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1113 FIB_SOURCE_DEFAULT_ROUTE);
1114 mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, 0,
1115 MFIB_SOURCE_DEFAULT_ROUTE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001116
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001118 pg_node_t *pn;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 pn = pg_get_node (ip4_lookup_node.index);
1120 pn->unformat_edit = unformat_pg_ip4_header;
1121 }
1122
1123 {
1124 ethernet_arp_header_t h;
1125
Dave Barachb7b92992018-10-17 10:38:51 -04001126 clib_memset (&h, 0, sizeof (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128#define _16(f,v) h.f = clib_host_to_net_u16 (v);
1129#define _8(f,v) h.f = v;
1130 _16 (l2_type, ETHERNET_ARP_HARDWARE_TYPE_ethernet);
1131 _16 (l3_type, ETHERNET_TYPE_IP4);
1132 _8 (n_l2_address_bytes, 6);
1133 _8 (n_l3_address_bytes, 4);
1134 _16 (opcode, ETHERNET_ARP_OPCODE_request);
1135#undef _16
1136#undef _8
1137
Dave Barachd7cb1b52016-12-09 09:52:16 -05001138 vlib_packet_template_init (vm, &im->ip4_arp_request_packet_template,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001139 /* data */ &h,
1140 sizeof (h),
1141 /* alloc chunk size */ 8,
1142 "ip4 arp");
1143 }
1144
Dave Barach203c6322016-06-26 10:29:03 -04001145 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146}
1147
1148VLIB_INIT_FUNCTION (ip4_lookup_init);
1149
Dave Barachd7cb1b52016-12-09 09:52:16 -05001150typedef struct
1151{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001152 /* Adjacency taken. */
Vengada Govindanf1544482016-09-28 02:45:57 -07001153 u32 dpo_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001154 u32 flow_hash;
1155 u32 fib_index;
1156
1157 /* Packet data, possibly *after* rewrite. */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001158 u8 packet_data[64 - 1 * sizeof (u32)];
1159}
1160ip4_forward_next_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001162#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001163u8 *
1164format_ip4_forward_next_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165{
1166 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1167 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001168 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001169 u32 indent = format_get_indent (s);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001170 s = format (s, "%U%U",
John Loac8146c2016-09-27 17:44:02 -04001171 format_white_space, indent,
1172 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001173 return s;
1174}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001175#endif
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001176
Dave Barachd7cb1b52016-12-09 09:52:16 -05001177static u8 *
1178format_ip4_lookup_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001179{
1180 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1181 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001182 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001183 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184
John Loac8146c2016-09-27 17:44:02 -04001185 s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001186 t->fib_index, t->dpo_index, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001187 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001188 format_white_space, indent,
1189 format_ip4_header, t->packet_data, sizeof (t->packet_data));
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001190 return s;
1191}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192
Dave Barachd7cb1b52016-12-09 09:52:16 -05001193static u8 *
1194format_ip4_rewrite_trace (u8 * s, va_list * args)
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001195{
1196 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1197 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001198 ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *);
Christophe Fontained3c008d2017-10-02 18:10:54 +02001199 u32 indent = format_get_indent (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
Vengada Govindanf1544482016-09-28 02:45:57 -07001201 s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001202 t->fib_index, t->dpo_index, format_ip_adjacency,
1203 t->dpo_index, FORMAT_IP_ADJACENCY_NONE, t->flow_hash);
Pierre Pfistera38c3df2016-06-13 10:28:09 +01001204 s = format (s, "\n%U%U",
Dave Barachd7cb1b52016-12-09 09:52:16 -05001205 format_white_space, indent,
1206 format_ip_adjacency_packet_data,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001207 t->packet_data, sizeof (t->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 return s;
1209}
1210
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001211#ifndef CLIB_MARCH_VARIANT
Ed Warnickecb9cada2015-12-08 15:45:58 -07001212/* Common trace function for all ip4-forward next nodes. */
1213void
1214ip4_forward_next_trace (vlib_main_t * vm,
1215 vlib_node_runtime_t * node,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001216 vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001217{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001218 u32 *from, n_left;
1219 ip4_main_t *im = &ip4_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001220
1221 n_left = frame->n_vectors;
1222 from = vlib_frame_vector_args (frame);
Dave Barach75fc8542016-10-11 16:16:02 -04001223
Ed Warnickecb9cada2015-12-08 15:45:58 -07001224 while (n_left >= 4)
1225 {
1226 u32 bi0, bi1;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001227 vlib_buffer_t *b0, *b1;
1228 ip4_forward_next_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229
1230 /* Prefetch next iteration. */
1231 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1232 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1233
1234 bi0 = from[0];
1235 bi1 = from[1];
1236
1237 b0 = vlib_get_buffer (vm, bi0);
1238 b1 = vlib_get_buffer (vm, bi1);
1239
1240 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1241 {
1242 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001243 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001244 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001245 t0->fib_index =
1246 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1247 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1248 vec_elt (im->fib_index_by_sw_if_index,
1249 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Pierre Pfister0febaf12016-06-08 12:23:21 +01001250
Dave Barach178cf492018-11-13 16:34:13 -05001251 clib_memcpy_fast (t0->packet_data,
1252 vlib_buffer_get_current (b0),
1253 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254 }
1255 if (b1->flags & VLIB_BUFFER_IS_TRACED)
1256 {
1257 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001258 t1->dpo_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259 t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001260 t1->fib_index =
1261 (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1262 (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1263 vec_elt (im->fib_index_by_sw_if_index,
1264 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001265 clib_memcpy_fast (t1->packet_data, vlib_buffer_get_current (b1),
1266 sizeof (t1->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267 }
1268 from += 2;
1269 n_left -= 2;
1270 }
1271
1272 while (n_left >= 1)
1273 {
1274 u32 bi0;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001275 vlib_buffer_t *b0;
1276 ip4_forward_next_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277
1278 bi0 = from[0];
1279
1280 b0 = vlib_get_buffer (vm, bi0);
1281
1282 if (b0->flags & VLIB_BUFFER_IS_TRACED)
1283 {
1284 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
Vengada Govindanf1544482016-09-28 02:45:57 -07001285 t0->dpo_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286 t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001287 t0->fib_index =
1288 (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1289 (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1290 vec_elt (im->fib_index_by_sw_if_index,
1291 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
Dave Barach178cf492018-11-13 16:34:13 -05001292 clib_memcpy_fast (t0->packet_data, vlib_buffer_get_current (b0),
1293 sizeof (t0->packet_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294 }
1295 from += 1;
1296 n_left -= 1;
1297 }
1298}
1299
Ed Warnickecb9cada2015-12-08 15:45:58 -07001300/* Compute TCP/UDP/ICMP4 checksum in software. */
1301u16
1302ip4_tcp_udp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
1303 ip4_header_t * ip0)
1304{
1305 ip_csum_t sum0;
1306 u32 ip_header_length, payload_length_host_byte_order;
Dave Barach75fc8542016-10-11 16:16:02 -04001307
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308 /* Initialize checksum with ip header. */
1309 ip_header_length = ip4_header_bytes (ip0);
Dave Barachd7cb1b52016-12-09 09:52:16 -05001310 payload_length_host_byte_order =
1311 clib_net_to_host_u16 (ip0->length) - ip_header_length;
1312 sum0 =
1313 clib_host_to_net_u32 (payload_length_host_byte_order +
1314 (ip0->protocol << 16));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001315
1316 if (BITS (uword) == 32)
1317 {
Dave Barachd7cb1b52016-12-09 09:52:16 -05001318 sum0 =
1319 ip_csum_with_carry (sum0,
1320 clib_mem_unaligned (&ip0->src_address, u32));
1321 sum0 =
1322 ip_csum_with_carry (sum0,
1323 clib_mem_unaligned (&ip0->dst_address, u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324 }
1325 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05001326 sum0 =
1327 ip_csum_with_carry (sum0, clib_mem_unaligned (&ip0->src_address, u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328
Srikanth A02833ff2019-10-02 17:48:58 -07001329 return ip_calculate_l4_checksum (vm, p0, sum0,
1330 payload_length_host_byte_order, (u8 *) ip0,
1331 ip_header_length, NULL);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001332}
1333
John Lo37682e12016-11-30 12:51:39 -05001334u32
Ed Warnickecb9cada2015-12-08 15:45:58 -07001335ip4_tcp_udp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0)
1336{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001337 ip4_header_t *ip0 = vlib_buffer_get_current (p0);
1338 udp_header_t *udp0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339 u16 sum16;
1340
1341 ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1342 || ip0->protocol == IP_PROTOCOL_UDP);
1343
1344 udp0 = (void *) (ip0 + 1);
1345 if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1346 {
Damjan Marion213b5aa2017-07-13 21:19:27 +02001347 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1348 | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349 return p0->flags;
1350 }
1351
1352 sum16 = ip4_tcp_udp_compute_checksum (vm, p0, ip0);
1353
Damjan Marion213b5aa2017-07-13 21:19:27 +02001354 p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1355 | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001356
1357 return p0->flags;
1358}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001359#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001360
Dave Barach68b0fb02017-02-28 15:15:56 -05001361/* *INDENT-OFF* */
1362VNET_FEATURE_ARC_INIT (ip4_local) =
1363{
1364 .arc_name = "ip4-local",
1365 .start_nodes = VNET_FEATURES ("ip4-local"),
Dave Baracha25def72018-11-26 11:04:45 -05001366 .last_in_arc = "ip4-local-end-of-arc",
Dave Barach68b0fb02017-02-28 15:15:56 -05001367};
1368/* *INDENT-ON* */
1369
Florin Coras20a14b92017-08-15 22:47:22 -07001370static inline void
Florin Coras1b255522018-06-01 12:22:23 -07001371ip4_local_l4_csum_validate (vlib_main_t * vm, vlib_buffer_t * p,
1372 ip4_header_t * ip, u8 is_udp, u8 * error,
1373 u8 * good_tcp_udp)
Florin Coras20a14b92017-08-15 22:47:22 -07001374{
1375 u32 flags0;
1376 flags0 = ip4_tcp_udp_validate_checksum (vm, p);
1377 *good_tcp_udp = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1378 if (is_udp)
1379 {
1380 udp_header_t *udp;
1381 u32 ip_len, udp_len;
1382 i32 len_diff;
1383 udp = ip4_next_header (ip);
1384 /* Verify UDP length. */
1385 ip_len = clib_net_to_host_u16 (ip->length);
1386 udp_len = clib_net_to_host_u16 (udp->length);
1387
1388 len_diff = ip_len - udp_len;
1389 *good_tcp_udp &= len_diff >= 0;
1390 *error = len_diff < 0 ? IP4_ERROR_UDP_LENGTH : *error;
1391 }
1392}
1393
Florin Coras1b255522018-06-01 12:22:23 -07001394#define ip4_local_csum_is_offloaded(_b) \
1395 _b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM \
1396 || _b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM
1397
1398#define ip4_local_need_csum_check(is_tcp_udp, _b) \
1399 (is_tcp_udp && !(_b->flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED \
1400 || ip4_local_csum_is_offloaded (_b)))
1401
1402#define ip4_local_csum_is_valid(_b) \
1403 (_b->flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT \
1404 || (ip4_local_csum_is_offloaded (_b))) != 0
1405
1406static inline void
1407ip4_local_check_l4_csum (vlib_main_t * vm, vlib_buffer_t * b,
1408 ip4_header_t * ih, u8 * error)
1409{
1410 u8 is_udp, is_tcp_udp, good_tcp_udp;
1411
1412 is_udp = ih->protocol == IP_PROTOCOL_UDP;
1413 is_tcp_udp = is_udp || ih->protocol == IP_PROTOCOL_TCP;
1414
1415 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp, b)))
1416 ip4_local_l4_csum_validate (vm, b, ih, is_udp, error, &good_tcp_udp);
1417 else
1418 good_tcp_udp = ip4_local_csum_is_valid (b);
1419
1420 ASSERT (IP4_ERROR_TCP_CHECKSUM + 1 == IP4_ERROR_UDP_CHECKSUM);
1421 *error = (is_tcp_udp && !good_tcp_udp
1422 ? IP4_ERROR_TCP_CHECKSUM + is_udp : *error);
1423}
1424
1425static inline void
1426ip4_local_check_l4_csum_x2 (vlib_main_t * vm, vlib_buffer_t ** b,
1427 ip4_header_t ** ih, u8 * error)
1428{
1429 u8 is_udp[2], is_tcp_udp[2], good_tcp_udp[2];
1430
1431 is_udp[0] = ih[0]->protocol == IP_PROTOCOL_UDP;
1432 is_udp[1] = ih[1]->protocol == IP_PROTOCOL_UDP;
1433
1434 is_tcp_udp[0] = is_udp[0] || ih[0]->protocol == IP_PROTOCOL_TCP;
1435 is_tcp_udp[1] = is_udp[1] || ih[1]->protocol == IP_PROTOCOL_TCP;
1436
1437 good_tcp_udp[0] = ip4_local_csum_is_valid (b[0]);
1438 good_tcp_udp[1] = ip4_local_csum_is_valid (b[1]);
1439
1440 if (PREDICT_FALSE (ip4_local_need_csum_check (is_tcp_udp[0], b[0])
1441 || ip4_local_need_csum_check (is_tcp_udp[1], b[1])))
1442 {
1443 if (is_tcp_udp[0])
1444 ip4_local_l4_csum_validate (vm, b[0], ih[0], is_udp[0], &error[0],
1445 &good_tcp_udp[0]);
1446 if (is_tcp_udp[1])
1447 ip4_local_l4_csum_validate (vm, b[1], ih[1], is_udp[1], &error[1],
1448 &good_tcp_udp[1]);
1449 }
1450
1451 error[0] = (is_tcp_udp[0] && !good_tcp_udp[0] ?
1452 IP4_ERROR_TCP_CHECKSUM + is_udp[0] : error[0]);
1453 error[1] = (is_tcp_udp[1] && !good_tcp_udp[1] ?
1454 IP4_ERROR_TCP_CHECKSUM + is_udp[1] : error[1]);
1455}
1456
1457static inline void
1458ip4_local_set_next_and_error (vlib_node_runtime_t * error_node,
1459 vlib_buffer_t * b, u16 * next, u8 error,
1460 u8 head_of_feature_arc)
1461{
1462 u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
1463 u32 next_index;
1464
1465 *next = error != IP4_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : *next;
1466 b->error = error ? error_node->errors[error] : 0;
1467 if (head_of_feature_arc)
1468 {
1469 next_index = *next;
1470 if (PREDICT_TRUE (error == (u8) IP4_ERROR_UNKNOWN_PROTOCOL))
1471 {
1472 vnet_feature_arc_start (arc_index,
1473 vnet_buffer (b)->sw_if_index[VLIB_RX],
1474 &next_index, b);
1475 *next = next_index;
1476 }
1477 }
1478}
1479
1480typedef struct
1481{
1482 ip4_address_t src;
1483 u32 lbi;
1484 u8 error;
Neale Rannsbe2286b2018-12-09 12:54:51 -08001485 u8 first;
Florin Coras1b255522018-06-01 12:22:23 -07001486} ip4_local_last_check_t;
1487
1488static inline void
1489ip4_local_check_src (vlib_buffer_t * b, ip4_header_t * ip0,
1490 ip4_local_last_check_t * last_check, u8 * error0)
1491{
1492 ip4_fib_mtrie_leaf_t leaf0;
1493 ip4_fib_mtrie_t *mtrie0;
1494 const dpo_id_t *dpo0;
1495 load_balance_t *lb0;
1496 u32 lbi0;
1497
1498 vnet_buffer (b)->ip.fib_index =
1499 vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0 ?
1500 vnet_buffer (b)->sw_if_index[VLIB_TX] : vnet_buffer (b)->ip.fib_index;
1501
Matthew Smith44e60462019-07-06 19:27:29 -05001502 /*
1503 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1504 * adjacency for the destination address (the local interface address).
1505 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1506 * adjacency for the source address (the remote sender's address)
1507 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301508 if (PREDICT_TRUE (last_check->src.as_u32 != ip0->src_address.as_u32) ||
1509 last_check->first)
Florin Coras1b255522018-06-01 12:22:23 -07001510 {
1511 mtrie0 = &ip4_fib_get (vnet_buffer (b)->ip.fib_index)->mtrie;
1512 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, &ip0->src_address);
1513 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 2);
1514 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, &ip0->src_address, 3);
1515 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
1516
Matthew Smith44e60462019-07-06 19:27:29 -05001517 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1518 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001519 vnet_buffer (b)->ip.adj_index[VLIB_TX] = lbi0;
Florin Coras1b255522018-06-01 12:22:23 -07001520
1521 lb0 = load_balance_get (lbi0);
1522 dpo0 = load_balance_get_bucket_i (lb0, 0);
1523
1524 /*
1525 * Must have a route to source otherwise we drop the packet.
1526 * ip4 broadcasts are accepted, e.g. to make dhcp client work
1527 *
1528 * The checks are:
1529 * - the source is a recieve => it's from us => bogus, do this
1530 * first since it sets a different error code.
1531 * - uRPF check for any route to source - accept if passes.
1532 * - allow packets destined to the broadcast address from unknown sources
1533 */
1534
1535 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1536 && dpo0->dpoi_type == DPO_RECEIVE) ?
1537 IP4_ERROR_SPOOFED_LOCAL_PACKETS : *error0);
1538 *error0 = ((*error0 == IP4_ERROR_UNKNOWN_PROTOCOL
1539 && !fib_urpf_check_size (lb0->lb_urpf)
1540 && ip0->dst_address.as_u32 != 0xFFFFFFFF) ?
1541 IP4_ERROR_SRC_LOOKUP_MISS : *error0);
1542
1543 last_check->src.as_u32 = ip0->src_address.as_u32;
1544 last_check->lbi = lbi0;
1545 last_check->error = *error0;
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301546 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001547 }
1548 else
1549 {
Matthew Smith44e60462019-07-06 19:27:29 -05001550 vnet_buffer (b)->ip.adj_index[VLIB_RX] =
1551 vnet_buffer (b)->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001552 vnet_buffer (b)->ip.adj_index[VLIB_TX] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001553 *error0 = last_check->error;
1554 }
1555}
1556
1557static inline void
1558ip4_local_check_src_x2 (vlib_buffer_t ** b, ip4_header_t ** ip,
1559 ip4_local_last_check_t * last_check, u8 * error)
1560{
1561 ip4_fib_mtrie_leaf_t leaf[2];
1562 ip4_fib_mtrie_t *mtrie[2];
1563 const dpo_id_t *dpo[2];
1564 load_balance_t *lb[2];
Neale Rannsbe2286b2018-12-09 12:54:51 -08001565 u32 not_last_hit;
Florin Coras1b255522018-06-01 12:22:23 -07001566 u32 lbi[2];
1567
Neale Rannsbe2286b2018-12-09 12:54:51 -08001568 not_last_hit = last_check->first;
Florin Coras1b255522018-06-01 12:22:23 -07001569 not_last_hit |= ip[0]->src_address.as_u32 ^ last_check->src.as_u32;
1570 not_last_hit |= ip[1]->src_address.as_u32 ^ last_check->src.as_u32;
1571
1572 vnet_buffer (b[0])->ip.fib_index =
1573 vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1574 vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1575 vnet_buffer (b[0])->ip.fib_index;
1576
1577 vnet_buffer (b[1])->ip.fib_index =
1578 vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1579 vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1580 vnet_buffer (b[1])->ip.fib_index;
1581
Matthew Smith44e60462019-07-06 19:27:29 -05001582 /*
1583 * vnet_buffer()->ip.adj_index[VLIB_RX] will be set to the index of the
1584 * adjacency for the destination address (the local interface address).
1585 * vnet_buffer()->ip.adj_index[VLIB_TX] will be set to the index of the
1586 * adjacency for the source address (the remote sender's address)
1587 */
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301588 if (PREDICT_TRUE (not_last_hit))
Florin Coras1b255522018-06-01 12:22:23 -07001589 {
1590 mtrie[0] = &ip4_fib_get (vnet_buffer (b[0])->ip.fib_index)->mtrie;
1591 mtrie[1] = &ip4_fib_get (vnet_buffer (b[1])->ip.fib_index)->mtrie;
1592
1593 leaf[0] = ip4_fib_mtrie_lookup_step_one (mtrie[0], &ip[0]->src_address);
1594 leaf[1] = ip4_fib_mtrie_lookup_step_one (mtrie[1], &ip[1]->src_address);
1595
1596 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1597 &ip[0]->src_address, 2);
1598 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1599 &ip[1]->src_address, 2);
1600
1601 leaf[0] = ip4_fib_mtrie_lookup_step (mtrie[0], leaf[0],
1602 &ip[0]->src_address, 3);
1603 leaf[1] = ip4_fib_mtrie_lookup_step (mtrie[1], leaf[1],
1604 &ip[1]->src_address, 3);
1605
1606 lbi[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf[0]);
1607 lbi[1] = ip4_fib_mtrie_leaf_get_adj_index (leaf[1]);
1608
Matthew Smith44e60462019-07-06 19:27:29 -05001609 vnet_buffer (b[0])->ip.adj_index[VLIB_RX] =
1610 vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001611 vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = lbi[0];
Florin Coras1b255522018-06-01 12:22:23 -07001612
Matthew Smith44e60462019-07-06 19:27:29 -05001613 vnet_buffer (b[1])->ip.adj_index[VLIB_RX] =
1614 vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
Florin Coras1b255522018-06-01 12:22:23 -07001615 vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = lbi[1];
Florin Coras1b255522018-06-01 12:22:23 -07001616
1617 lb[0] = load_balance_get (lbi[0]);
1618 lb[1] = load_balance_get (lbi[1]);
1619
1620 dpo[0] = load_balance_get_bucket_i (lb[0], 0);
1621 dpo[1] = load_balance_get_bucket_i (lb[1], 0);
1622
1623 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1624 dpo[0]->dpoi_type == DPO_RECEIVE) ?
1625 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[0]);
1626 error[0] = ((error[0] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1627 !fib_urpf_check_size (lb[0]->lb_urpf) &&
1628 ip[0]->dst_address.as_u32 != 0xFFFFFFFF)
1629 ? IP4_ERROR_SRC_LOOKUP_MISS : error[0]);
1630
1631 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1632 dpo[1]->dpoi_type == DPO_RECEIVE) ?
1633 IP4_ERROR_SPOOFED_LOCAL_PACKETS : error[1]);
1634 error[1] = ((error[1] == IP4_ERROR_UNKNOWN_PROTOCOL &&
1635 !fib_urpf_check_size (lb[1]->lb_urpf) &&
1636 ip[1]->dst_address.as_u32 != 0xFFFFFFFF)
1637 ? IP4_ERROR_SRC_LOOKUP_MISS : error[1]);
1638
1639 last_check->src.as_u32 = ip[1]->src_address.as_u32;
1640 last_check->lbi = lbi[1];
1641 last_check->error = error[1];
Nitin Saxena2d18d2e2020-01-04 12:28:42 +05301642 last_check->first = 0;
Florin Coras1b255522018-06-01 12:22:23 -07001643 }
1644 else
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] = last_check->lbi;
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] = last_check->lbi;
Florin Coras1b255522018-06-01 12:22:23 -07001653
1654 error[0] = last_check->error;
1655 error[1] = last_check->error;
1656 }
1657}
Florin Coras20a14b92017-08-15 22:47:22 -07001658
Florin Corasc67cfd22018-10-01 21:59:18 -07001659enum ip_local_packet_type_e
1660{
1661 IP_LOCAL_PACKET_TYPE_L4,
1662 IP_LOCAL_PACKET_TYPE_NAT,
Juraj Sloboda3048b632018-10-02 11:13:53 +02001663 IP_LOCAL_PACKET_TYPE_FRAG,
Florin Corasc67cfd22018-10-01 21:59:18 -07001664};
1665
1666/**
1667 * Determine packet type and next node.
1668 *
1669 * The expectation is that all packets that are not L4 will skip
1670 * checksums and source checks.
1671 */
1672always_inline u8
1673ip4_local_classify (vlib_buffer_t * b, ip4_header_t * ip, u16 * next)
1674{
1675 ip_lookup_main_t *lm = &ip4_main.lookup_main;
1676
Juraj Sloboda3048b632018-10-02 11:13:53 +02001677 if (PREDICT_FALSE (ip4_is_fragment (ip)))
1678 {
1679 *next = IP_LOCAL_NEXT_REASSEMBLY;
1680 return IP_LOCAL_PACKET_TYPE_FRAG;
1681 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001682 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_IS_NATED))
1683 {
1684 *next = lm->local_next_by_ip_protocol[ip->protocol];
1685 return IP_LOCAL_PACKET_TYPE_NAT;
1686 }
1687
1688 *next = lm->local_next_by_ip_protocol[ip->protocol];
1689 return IP_LOCAL_PACKET_TYPE_L4;
1690}
1691
Dave Barach68b0fb02017-02-28 15:15:56 -05001692static inline uword
1693ip4_local_inline (vlib_main_t * vm,
1694 vlib_node_runtime_t * node,
1695 vlib_frame_t * frame, int head_of_feature_arc)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001696{
Florin Coras1b255522018-06-01 12:22:23 -07001697 u32 *from, n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05001698 vlib_node_runtime_t *error_node =
1699 vlib_node_get_runtime (vm, ip4_input_node.index);
Florin Coras1b255522018-06-01 12:22:23 -07001700 u16 nexts[VLIB_FRAME_SIZE], *next;
1701 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1702 ip4_header_t *ip[2];
Florin Corasc67cfd22018-10-01 21:59:18 -07001703 u8 error[2], pt[2];
Florin Coras1b255522018-06-01 12:22:23 -07001704
1705 ip4_local_last_check_t last_check = {
Neale Rannsbe2286b2018-12-09 12:54:51 -08001706 /*
1707 * 0.0.0.0 can appear as the source address of an IP packet,
1708 * as can any other address, hence the need to use the 'first'
1709 * member to make sure the .lbi is initialised for the first
1710 * packet.
1711 */
Florin Coras1b255522018-06-01 12:22:23 -07001712 .src = {.as_u32 = 0},
1713 .lbi = ~0,
Neale Rannsbe2286b2018-12-09 12:54:51 -08001714 .error = IP4_ERROR_UNKNOWN_PROTOCOL,
1715 .first = 1,
Florin Coras1b255522018-06-01 12:22:23 -07001716 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07001717
1718 from = vlib_frame_vector_args (frame);
1719 n_left_from = frame->n_vectors;
Dave Barach75fc8542016-10-11 16:16:02 -04001720
Ed Warnickecb9cada2015-12-08 15:45:58 -07001721 if (node->flags & VLIB_NODE_FLAG_TRACE)
1722 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
1723
Florin Coras1b255522018-06-01 12:22:23 -07001724 vlib_get_buffers (vm, from, bufs, n_left_from);
1725 b = bufs;
1726 next = nexts;
1727
1728 while (n_left_from >= 6)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001729 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001730 u8 not_batch = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001731
Florin Coras1b255522018-06-01 12:22:23 -07001732 /* Prefetch next iteration. */
1733 {
1734 vlib_prefetch_buffer_header (b[4], LOAD);
1735 vlib_prefetch_buffer_header (b[5], LOAD);
1736
1737 CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1738 CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
1739 }
1740
1741 error[0] = error[1] = IP4_ERROR_UNKNOWN_PROTOCOL;
1742
1743 ip[0] = vlib_buffer_get_current (b[0]);
1744 ip[1] = vlib_buffer_get_current (b[1]);
1745
1746 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1747 vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1748
Florin Corasc67cfd22018-10-01 21:59:18 -07001749 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
1750 pt[1] = ip4_local_classify (b[1], ip[1], &next[1]);
Florin Coras1b255522018-06-01 12:22:23 -07001751
Florin Corasc67cfd22018-10-01 21:59:18 -07001752 not_batch = pt[0] ^ pt[1];
1753
1754 if (head_of_feature_arc == 0 || (pt[0] && not_batch == 0))
Florin Coras1b255522018-06-01 12:22:23 -07001755 goto skip_checks;
1756
1757 if (PREDICT_TRUE (not_batch == 0))
Dave Barachd7cb1b52016-12-09 09:52:16 -05001758 {
Florin Coras1b255522018-06-01 12:22:23 -07001759 ip4_local_check_l4_csum_x2 (vm, b, ip, error);
1760 ip4_local_check_src_x2 (b, ip, &last_check, error);
1761 }
1762 else
1763 {
Florin Corasc67cfd22018-10-01 21:59:18 -07001764 if (!pt[0])
Florin Coras20a14b92017-08-15 22:47:22 -07001765 {
Florin Coras1b255522018-06-01 12:22:23 -07001766 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1767 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
Florin Coras20a14b92017-08-15 22:47:22 -07001768 }
Florin Corasc67cfd22018-10-01 21:59:18 -07001769 if (!pt[1])
Ed Warnickecb9cada2015-12-08 15:45:58 -07001770 {
Florin Coras1b255522018-06-01 12:22:23 -07001771 ip4_local_check_l4_csum (vm, b[1], ip[1], &error[1]);
1772 ip4_local_check_src (b[1], ip[1], &last_check, &error[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001773 }
1774 }
1775
Florin Coras1b255522018-06-01 12:22:23 -07001776 skip_checks:
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001777
Florin Coras1b255522018-06-01 12:22:23 -07001778 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1779 head_of_feature_arc);
1780 ip4_local_set_next_and_error (error_node, b[1], &next[1], error[1],
1781 head_of_feature_arc);
Dave Barach75fc8542016-10-11 16:16:02 -04001782
Florin Coras1b255522018-06-01 12:22:23 -07001783 b += 2;
1784 next += 2;
1785 n_left_from -= 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001786 }
1787
Florin Coras1b255522018-06-01 12:22:23 -07001788 while (n_left_from > 0)
1789 {
1790 error[0] = IP4_ERROR_UNKNOWN_PROTOCOL;
1791
1792 ip[0] = vlib_buffer_get_current (b[0]);
1793 vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
Florin Corasc67cfd22018-10-01 21:59:18 -07001794 pt[0] = ip4_local_classify (b[0], ip[0], &next[0]);
Florin Coras1b255522018-06-01 12:22:23 -07001795
Florin Corasc67cfd22018-10-01 21:59:18 -07001796 if (head_of_feature_arc == 0 || pt[0])
Florin Coras1b255522018-06-01 12:22:23 -07001797 goto skip_check;
1798
1799 ip4_local_check_l4_csum (vm, b[0], ip[0], &error[0]);
1800 ip4_local_check_src (b[0], ip[0], &last_check, &error[0]);
1801
1802 skip_check:
1803
Florin Coras1b255522018-06-01 12:22:23 -07001804 ip4_local_set_next_and_error (error_node, b[0], &next[0], error[0],
1805 head_of_feature_arc);
1806
1807 b += 1;
1808 next += 1;
1809 n_left_from -= 1;
1810 }
1811
1812 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001813 return frame->n_vectors;
1814}
1815
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001816VLIB_NODE_FN (ip4_local_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1817 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001818{
1819 return ip4_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1820}
1821
1822/* *INDENT-OFF* */
Neale Ranns32e1c012016-11-22 17:07:28 +00001823VLIB_REGISTER_NODE (ip4_local_node) =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824{
Dave Barach68b0fb02017-02-28 15:15:56 -05001825 .name = "ip4-local",
1826 .vector_size = sizeof (u32),
1827 .format_trace = format_ip4_forward_next_trace,
1828 .n_next_nodes = IP_LOCAL_N_NEXT,
1829 .next_nodes =
Dave Barachd7cb1b52016-12-09 09:52:16 -05001830 {
Neale Rannsd91c1db2017-07-31 02:30:50 -07001831 [IP_LOCAL_NEXT_DROP] = "ip4-drop",
1832 [IP_LOCAL_NEXT_PUNT] = "ip4-punt",
Dave Barach68b0fb02017-02-28 15:15:56 -05001833 [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip4-udp-lookup",
Florin Coras20a14b92017-08-15 22:47:22 -07001834 [IP_LOCAL_NEXT_ICMP] = "ip4-icmp-input",
Klement Sekera896c8962019-06-24 11:52:49 +00001835 [IP_LOCAL_NEXT_REASSEMBLY] = "ip4-full-reassembly",
Florin Coras20a14b92017-08-15 22:47:22 -07001836 },
Dave Barach68b0fb02017-02-28 15:15:56 -05001837};
1838/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001839
Dave Barachd7cb1b52016-12-09 09:52:16 -05001840
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001841VLIB_NODE_FN (ip4_local_end_of_arc_node) (vlib_main_t * vm,
1842 vlib_node_runtime_t * node,
1843 vlib_frame_t * frame)
Dave Barach68b0fb02017-02-28 15:15:56 -05001844{
1845 return ip4_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1846}
1847
1848/* *INDENT-OFF* */
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001849VLIB_REGISTER_NODE (ip4_local_end_of_arc_node) = {
Dave Barach68b0fb02017-02-28 15:15:56 -05001850 .name = "ip4-local-end-of-arc",
1851 .vector_size = sizeof (u32),
1852
1853 .format_trace = format_ip4_forward_next_trace,
1854 .sibling_of = "ip4-local",
1855};
1856
Dave Barach68b0fb02017-02-28 15:15:56 -05001857VNET_FEATURE_INIT (ip4_local_end_of_arc, static) = {
1858 .arc_name = "ip4-local",
1859 .node_name = "ip4-local-end-of-arc",
1860 .runs_before = 0, /* not before any other features */
1861};
1862/* *INDENT-ON* */
1863
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001864#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05001865void
1866ip4_register_protocol (u32 protocol, u32 node_index)
1867{
1868 vlib_main_t *vm = vlib_get_main ();
1869 ip4_main_t *im = &ip4_main;
1870 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001871
1872 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
Dave Barachd7cb1b52016-12-09 09:52:16 -05001873 lm->local_next_by_ip_protocol[protocol] =
1874 vlib_node_add_next (vm, ip4_local_node.index, node_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001875}
Neale Rannsb538dd82019-05-21 06:54:54 -07001876
1877void
1878ip4_unregister_protocol (u32 protocol)
1879{
1880 ip4_main_t *im = &ip4_main;
1881 ip_lookup_main_t *lm = &im->lookup_main;
1882
1883 ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1884 lm->local_next_by_ip_protocol[protocol] = IP_LOCAL_NEXT_PUNT;
1885}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02001886#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001887
1888static clib_error_t *
1889show_ip_local_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05001890 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001891{
Dave Barachd7cb1b52016-12-09 09:52:16 -05001892 ip4_main_t *im = &ip4_main;
1893 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001894 int i;
1895
1896 vlib_cli_output (vm, "Protocols handled by ip4_local");
Dave Barachd7cb1b52016-12-09 09:52:16 -05001897 for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001898 {
1899 if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001900 {
1901 u32 node_index = vlib_get_node (vm,
1902 ip4_local_node.index)->
1903 next_nodes[lm->local_next_by_ip_protocol[i]];
Neale Rannsb538dd82019-05-21 06:54:54 -07001904 vlib_cli_output (vm, "%U: %U", format_ip_protocol, i,
1905 format_vlib_node_name, vm, node_index);
Pierre Pfister1bfd3722017-09-18 11:40:32 +02001906 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907 }
1908 return 0;
1909}
1910
1911
1912
Billy McFall0683c9c2016-10-13 08:27:31 -04001913/*?
1914 * Display the set of protocols handled by the local IPv4 stack.
1915 *
1916 * @cliexpar
1917 * Example of how to display local protocol table:
1918 * @cliexstart{show ip local}
1919 * Protocols handled by ip4_local
1920 * 1
1921 * 17
1922 * 47
1923 * @cliexend
1924?*/
1925/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05001926VLIB_CLI_COMMAND (show_ip_local, static) =
1927{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001928 .path = "show ip local",
1929 .function = show_ip_local_command_fn,
Billy McFall0683c9c2016-10-13 08:27:31 -04001930 .short_help = "show ip local",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001931};
Billy McFall0683c9c2016-10-13 08:27:31 -04001932/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001933
Dave Barachd7cb1b52016-12-09 09:52:16 -05001934typedef enum
1935{
Ed Warnickecb9cada2015-12-08 15:45:58 -07001936 IP4_REWRITE_NEXT_DROP,
Chris Luke816f3e12016-06-14 16:24:47 -04001937 IP4_REWRITE_NEXT_ICMP_ERROR,
Ole Troan313f7e22018-04-10 16:02:51 +02001938 IP4_REWRITE_NEXT_FRAGMENT,
1939 IP4_REWRITE_N_NEXT /* Last */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001940} ip4_rewrite_next_t;
1941
Neale Ranns889fe942017-06-01 05:43:19 -04001942/**
1943 * This bits of an IPv4 address to mask to construct a multicast
1944 * MAC address
1945 */
1946#if CLIB_ARCH_IS_BIG_ENDIAN
1947#define IP4_MCAST_ADDR_MASK 0x007fffff
1948#else
1949#define IP4_MCAST_ADDR_MASK 0xffff7f00
1950#endif
1951
Ole Troan8a9c8f12018-05-18 11:01:31 +02001952always_inline void
1953ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
Ole Troaneb284a12019-10-09 13:33:19 +02001954 u16 adj_packet_bytes, bool df, u16 * next,
1955 u8 is_midchain, u32 * error)
Ole Troan8a9c8f12018-05-18 11:01:31 +02001956{
1957 if (packet_len > adj_packet_bytes)
1958 {
1959 *error = IP4_ERROR_MTU_EXCEEDED;
1960 if (df)
1961 {
1962 icmp4_error_set_vnet_buffer
1963 (b, ICMP4_destination_unreachable,
1964 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
1965 adj_packet_bytes);
1966 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
1967 }
1968 else
1969 {
Ole Troan313f7e22018-04-10 16:02:51 +02001970 /* IP fragmentation */
Ole Troan282093f2018-09-19 12:38:51 +02001971 ip_frag_set_vnet_buffer (b, adj_packet_bytes,
Neale Ranns0b6a8572019-10-30 17:34:14 +00001972 (is_midchain ?
Ole Troaneb284a12019-10-09 13:33:19 +02001973 IP_FRAG_NEXT_IP_REWRITE_MIDCHAIN :
1974 IP_FRAG_NEXT_IP_REWRITE), 0);
Ole Troan313f7e22018-04-10 16:02:51 +02001975 *next = IP4_REWRITE_NEXT_FRAGMENT;
Ole Troan8a9c8f12018-05-18 11:01:31 +02001976 }
1977 }
1978}
1979
Neale Ranns0b6a8572019-10-30 17:34:14 +00001980/* increment TTL & update checksum.
1981 Works either endian, so no need for byte swap. */
1982static_always_inline void
1983ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
1984{
1985 i32 ttl;
1986 u32 checksum;
1987 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
1988 {
1989 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1990 return;
1991 }
1992
1993 ttl = ip->ttl;
1994
1995 checksum = ip->checksum - clib_host_to_net_u16 (0x0100);
1996 checksum += checksum >= 0xffff;
1997
1998 ip->checksum = checksum;
1999 ttl += 1;
2000 ip->ttl = ttl;
2001
2002 ASSERT (ip->checksum == ip4_header_checksum (ip));
2003}
2004
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002005/* Decrement TTL & update checksum.
2006 Works either endian, so no need for byte swap. */
2007static_always_inline void
2008ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
2009 u32 * error)
2010{
2011 i32 ttl;
2012 u32 checksum;
2013 if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
2014 {
2015 b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
2016 return;
2017 }
2018
2019 ttl = ip->ttl;
2020
2021 /* Input node should have reject packets with ttl 0. */
2022 ASSERT (ip->ttl > 0);
2023
2024 checksum = ip->checksum + clib_host_to_net_u16 (0x0100);
2025 checksum += checksum >= 0xffff;
2026
2027 ip->checksum = checksum;
2028 ttl -= 1;
2029 ip->ttl = ttl;
2030
2031 /*
2032 * If the ttl drops below 1 when forwarding, generate
2033 * an ICMP response.
2034 */
2035 if (PREDICT_FALSE (ttl <= 0))
2036 {
2037 *error = IP4_ERROR_TIME_EXPIRED;
2038 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2039 icmp4_error_set_vnet_buffer (b, ICMP4_time_exceeded,
2040 ICMP4_time_exceeded_ttl_exceeded_in_transit,
2041 0);
2042 *next = IP4_REWRITE_NEXT_ICMP_ERROR;
2043 }
2044
2045 /* Verify checksum. */
2046 ASSERT ((ip->checksum == ip4_header_checksum (ip)) ||
2047 (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM));
2048}
2049
2050
Ed Warnickecb9cada2015-12-08 15:45:58 -07002051always_inline uword
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002052ip4_rewrite_inline_with_gso (vlib_main_t * vm,
2053 vlib_node_runtime_t * node,
2054 vlib_frame_t * frame,
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002055 int do_counters, int is_midchain, int is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002056{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002057 ip_lookup_main_t *lm = &ip4_main.lookup_main;
2058 u32 *from = vlib_frame_vector_args (frame);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002059 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
2060 u16 nexts[VLIB_FRAME_SIZE], *next;
2061 u32 n_left_from;
Dave Barachd7cb1b52016-12-09 09:52:16 -05002062 vlib_node_runtime_t *error_node =
2063 vlib_node_get_runtime (vm, ip4_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002064
2065 n_left_from = frame->n_vectors;
Damjan Marion067cd622018-07-11 12:47:43 +02002066 u32 thread_index = vm->thread_index;
Dave Barach75fc8542016-10-11 16:16:02 -04002067
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002068 vlib_get_buffers (vm, from, bufs, n_left_from);
2069 clib_memset_u16 (nexts, IP4_REWRITE_NEXT_DROP, n_left_from);
2070
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002071#if (CLIB_N_PREFETCHES >= 8)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002072 if (n_left_from >= 6)
2073 {
2074 int i;
Simon Zhang5a5a8692018-11-26 17:15:24 +08002075 for (i = 2; i < 6; i++)
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002076 vlib_prefetch_buffer_header (bufs[i], LOAD);
2077 }
2078
2079 next = nexts;
2080 b = bufs;
2081 while (n_left_from >= 8)
2082 {
Neale Ranns960eeea2019-12-02 23:28:50 +00002083 const ip_adjacency_t *adj0, *adj1;
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002084 ip4_header_t *ip0, *ip1;
2085 u32 rw_len0, error0, adj_index0;
2086 u32 rw_len1, error1, adj_index1;
2087 u32 tx_sw_if_index0, tx_sw_if_index1;
2088 u8 *p;
2089
2090 vlib_prefetch_buffer_header (b[6], LOAD);
2091 vlib_prefetch_buffer_header (b[7], LOAD);
2092
2093 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2094 adj_index1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
2095
2096 /*
2097 * pre-fetch the per-adjacency counters
2098 */
2099 if (do_counters)
2100 {
2101 vlib_prefetch_combined_counter (&adjacency_counters,
2102 thread_index, adj_index0);
2103 vlib_prefetch_combined_counter (&adjacency_counters,
2104 thread_index, adj_index1);
2105 }
2106
2107 ip0 = vlib_buffer_get_current (b[0]);
2108 ip1 = vlib_buffer_get_current (b[1]);
2109
2110 error0 = error1 = IP4_ERROR_NONE;
2111
2112 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2113 ip4_ttl_and_checksum_check (b[1], ip1, next + 1, &error1);
2114
2115 /* Rewrite packet header and updates lengths. */
2116 adj0 = adj_get (adj_index0);
2117 adj1 = adj_get (adj_index1);
2118
2119 /* Worth pipelining. No guarantee that adj0,1 are hot... */
2120 rw_len0 = adj0[0].rewrite_header.data_bytes;
2121 rw_len1 = adj1[0].rewrite_header.data_bytes;
2122 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2123 vnet_buffer (b[1])->ip.save_rewrite_length = rw_len1;
2124
2125 p = vlib_buffer_get_current (b[2]);
2126 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2127 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2128
2129 p = vlib_buffer_get_current (b[3]);
2130 CLIB_PREFETCH (p - CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES, STORE);
2131 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
2132
2133 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002134 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2135 u16 ip1_len = clib_net_to_host_u16 (ip1->length);
2136
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002137 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002138 ip0_len = gso_mtu_sz (b[0]);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002139 if (b[1]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002140 ip1_len = gso_mtu_sz (b[1]);
2141
2142 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002143 adj0[0].rewrite_header.max_l3_packet_bytes,
2144 ip0->flags_and_fragment_offset &
2145 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002146 next + 0, is_midchain, &error0);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002147 ip4_mtu_check (b[1], ip1_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002148 adj1[0].rewrite_header.max_l3_packet_bytes,
2149 ip1->flags_and_fragment_offset &
2150 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002151 next + 1, is_midchain, &error1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002152
2153 if (is_mcast)
2154 {
2155 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2156 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2157 IP4_ERROR_SAME_INTERFACE : error0);
2158 error1 = ((adj1[0].rewrite_header.sw_if_index ==
2159 vnet_buffer (b[1])->sw_if_index[VLIB_RX]) ?
2160 IP4_ERROR_SAME_INTERFACE : error1);
2161 }
2162
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002163 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002164 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002165 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2166 {
2167 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002168 vlib_buffer_advance (b[0], -(word) rw_len0);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002169
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002170 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2171 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2172
2173 if (PREDICT_FALSE
2174 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2175 vnet_feature_arc_start (lm->output_feature_arc_index,
2176 tx_sw_if_index0, &next_index, b[0]);
2177 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002178 if (is_midchain)
2179 calc_checksums (vm, b[0]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002180 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002181 else
2182 {
2183 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002184 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2185 ip4_ttl_inc (b[0], ip0);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002186 }
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002187 if (PREDICT_TRUE (error1 == IP4_ERROR_NONE))
2188 {
2189 u32 next_index = adj1[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002190 vlib_buffer_advance (b[1], -(word) rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002191
2192 tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2193 vnet_buffer (b[1])->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2194
2195 if (PREDICT_FALSE
2196 (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2197 vnet_feature_arc_start (lm->output_feature_arc_index,
2198 tx_sw_if_index1, &next_index, b[1]);
2199 next[1] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002200 if (is_midchain)
2201 calc_checksums (vm, b[1]);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002202 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002203 else
2204 {
2205 b[1]->error = error_node->errors[error1];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002206 if (error1 == IP4_ERROR_MTU_EXCEEDED)
2207 ip4_ttl_inc (b[1], ip1);
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002208 }
Neale Ranns0b6a8572019-10-30 17:34:14 +00002209
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002210 /* Guess we are only writing on simple Ethernet header. */
2211 vnet_rewrite_two_headers (adj0[0], adj1[0],
2212 ip0, ip1, sizeof (ethernet_header_t));
2213
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002214 if (do_counters)
2215 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002216 if (error0 == IP4_ERROR_NONE)
2217 vlib_increment_combined_counter
2218 (&adjacency_counters,
2219 thread_index,
2220 adj_index0, 1,
2221 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002222
Neale Ranns0b6a8572019-10-30 17:34:14 +00002223 if (error1 == IP4_ERROR_NONE)
2224 vlib_increment_combined_counter
2225 (&adjacency_counters,
2226 thread_index,
2227 adj_index1, 1,
2228 vlib_buffer_length_in_chain (vm, b[1]) + rw_len1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002229 }
2230
2231 if (is_midchain)
2232 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002233 if (error0 == IP4_ERROR_NONE && adj0->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002234 adj0->sub_type.midchain.fixup_func
2235 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
Neale Ranns0b6a8572019-10-30 17:34:14 +00002236 if (error1 == IP4_ERROR_NONE && adj1->sub_type.midchain.fixup_func)
Neale Ranns25edf142019-03-22 08:12:48 +00002237 adj1->sub_type.midchain.fixup_func
2238 (vm, adj1, b[1], adj1->sub_type.midchain.fixup_data);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002239 }
2240
2241 if (is_mcast)
2242 {
Neale Ranns0b6a8572019-10-30 17:34:14 +00002243 /* copy bytes from the IP address into the MAC rewrite */
2244 if (error0 == IP4_ERROR_NONE)
2245 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2246 adj0->rewrite_header.dst_mcast_offset,
2247 &ip0->dst_address.as_u32, (u8 *) ip0);
2248 if (error1 == IP4_ERROR_NONE)
2249 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2250 adj1->rewrite_header.dst_mcast_offset,
2251 &ip1->dst_address.as_u32, (u8 *) ip1);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002252 }
2253
2254 next += 2;
2255 b += 2;
2256 n_left_from -= 2;
2257 }
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002258#elif (CLIB_N_PREFETCHES >= 4)
2259 next = nexts;
2260 b = bufs;
2261 while (n_left_from >= 1)
2262 {
2263 ip_adjacency_t *adj0;
2264 ip4_header_t *ip0;
2265 u32 rw_len0, error0, adj_index0;
2266 u32 tx_sw_if_index0;
2267 u8 *p;
2268
2269 /* Prefetch next iteration */
2270 if (PREDICT_TRUE (n_left_from >= 4))
2271 {
2272 ip_adjacency_t *adj2;
2273 u32 adj_index2;
2274
2275 vlib_prefetch_buffer_header (b[3], LOAD);
2276 vlib_prefetch_buffer_data (b[2], LOAD);
2277
2278 /* Prefetch adj->rewrite_header */
2279 adj_index2 = vnet_buffer (b[2])->ip.adj_index[VLIB_TX];
2280 adj2 = adj_get (adj_index2);
2281 p = (u8 *) adj2;
2282 CLIB_PREFETCH (p + CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES,
2283 LOAD);
2284 }
2285
2286 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2287
2288 /*
2289 * Prefetch the per-adjacency counters
2290 */
2291 if (do_counters)
2292 {
2293 vlib_prefetch_combined_counter (&adjacency_counters,
2294 thread_index, adj_index0);
2295 }
2296
2297 ip0 = vlib_buffer_get_current (b[0]);
2298
2299 error0 = IP4_ERROR_NONE;
2300
2301 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2302
2303 /* Rewrite packet header and updates lengths. */
2304 adj0 = adj_get (adj_index0);
2305
2306 /* Rewrite header was prefetched. */
2307 rw_len0 = adj0[0].rewrite_header.data_bytes;
2308 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2309
2310 /* Check MTU of outgoing interface. */
2311 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
2312
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002313 if (b[0]->flags & VNET_BUFFER_F_GSO)
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002314 ip0_len = gso_mtu_sz (b[0]);
2315
2316 ip4_mtu_check (b[0], ip0_len,
2317 adj0[0].rewrite_header.max_l3_packet_bytes,
2318 ip0->flags_and_fragment_offset &
2319 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002320 next + 0, is_midchain, &error0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002321
2322 if (is_mcast)
2323 {
2324 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2325 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2326 IP4_ERROR_SAME_INTERFACE : error0);
2327 }
2328
2329 /* Don't adjust the buffer for ttl issue; icmp-error node wants
2330 * to see the IP header */
2331 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2332 {
2333 u32 next_index = adj0[0].rewrite_header.next_index;
2334 vlib_buffer_advance (b[0], -(word) rw_len0);
2335 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2336 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2337
2338 if (PREDICT_FALSE
2339 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2340 vnet_feature_arc_start (lm->output_feature_arc_index,
2341 tx_sw_if_index0, &next_index, b[0]);
2342 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002343
2344 if (is_midchain)
2345 calc_checksums (vm, b[0]);
2346
2347 /* Guess we are only writing on simple Ethernet header. */
2348 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2349
2350 /*
2351 * Bump the per-adjacency counters
2352 */
2353 if (do_counters)
2354 vlib_increment_combined_counter
2355 (&adjacency_counters,
2356 thread_index,
2357 adj_index0, 1, vlib_buffer_length_in_chain (vm,
2358 b[0]) + rw_len0);
2359
2360 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2361 adj0->sub_type.midchain.fixup_func
2362 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2363
2364 if (is_mcast)
2365 /* copy bytes from the IP address into the MAC rewrite */
2366 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2367 adj0->rewrite_header.dst_mcast_offset,
2368 &ip0->dst_address.as_u32, (u8 *) ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002369 }
2370 else
2371 {
2372 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002373 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2374 ip4_ttl_inc (b[0], ip0);
Lijian.Zhang840f64b2019-07-09 17:54:32 +08002375 }
2376
2377 next += 1;
2378 b += 1;
2379 n_left_from -= 1;
2380 }
2381#endif
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002382
Ed Warnickecb9cada2015-12-08 15:45:58 -07002383 while (n_left_from > 0)
2384 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002385 ip_adjacency_t *adj0;
2386 ip4_header_t *ip0;
2387 u32 rw_len0, adj_index0, error0;
2388 u32 tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002390 adj_index0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
2391
2392 adj0 = adj_get (adj_index0);
2393
2394 if (do_counters)
2395 vlib_prefetch_combined_counter (&adjacency_counters,
2396 thread_index, adj_index0);
2397
2398 ip0 = vlib_buffer_get_current (b[0]);
2399
2400 error0 = IP4_ERROR_NONE;
2401
2402 ip4_ttl_and_checksum_check (b[0], ip0, next + 0, &error0);
2403
2404
2405 /* Update packet buffer attributes/set output interface. */
2406 rw_len0 = adj0[0].rewrite_header.data_bytes;
2407 vnet_buffer (b[0])->ip.save_rewrite_length = rw_len0;
2408
2409 /* Check MTU of outgoing interface. */
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002410 u16 ip0_len = clib_net_to_host_u16 (ip0->length);
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002411 if (b[0]->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002412 ip0_len = gso_mtu_sz (b[0]);
2413
2414 ip4_mtu_check (b[0], ip0_len,
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002415 adj0[0].rewrite_header.max_l3_packet_bytes,
2416 ip0->flags_and_fragment_offset &
2417 clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT),
Ole Troaneb284a12019-10-09 13:33:19 +02002418 next + 0, is_midchain, &error0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002419
2420 if (is_mcast)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421 {
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002422 error0 = ((adj0[0].rewrite_header.sw_if_index ==
2423 vnet_buffer (b[0])->sw_if_index[VLIB_RX]) ?
2424 IP4_ERROR_SAME_INTERFACE : error0);
2425 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002426
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002427 /* Don't adjust the buffer for ttl issue; icmp-error node wants
Jim Thompsonf324dec2019-04-08 03:22:21 -05002428 * to see the IP header */
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002429 if (PREDICT_TRUE (error0 == IP4_ERROR_NONE))
2430 {
2431 u32 next_index = adj0[0].rewrite_header.next_index;
Zhiyong Yanga6659212019-06-25 22:41:55 -04002432 vlib_buffer_advance (b[0], -(word) rw_len0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002433 tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2434 vnet_buffer (b[0])->sw_if_index[VLIB_TX] = tx_sw_if_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002435
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002436 if (PREDICT_FALSE
2437 (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2438 vnet_feature_arc_start (lm->output_feature_arc_index,
2439 tx_sw_if_index0, &next_index, b[0]);
2440 next[0] = next_index;
Neale Ranns0b6a8572019-10-30 17:34:14 +00002441
2442 if (is_midchain)
2443 /* this acts on the packet that is about to be encapped */
2444 calc_checksums (vm, b[0]);
2445
2446 /* Guess we are only writing on simple Ethernet header. */
2447 vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2448
2449 if (do_counters)
2450 vlib_increment_combined_counter
2451 (&adjacency_counters,
2452 thread_index, adj_index0, 1,
2453 vlib_buffer_length_in_chain (vm, b[0]) + rw_len0);
2454
2455 if (is_midchain && adj0->sub_type.midchain.fixup_func)
2456 adj0->sub_type.midchain.fixup_func
2457 (vm, adj0, b[0], adj0->sub_type.midchain.fixup_data);
2458
2459 if (is_mcast)
2460 /* copy bytes from the IP address into the MAC rewrite */
2461 vnet_ip_mcast_fixup_header (IP4_MCAST_ADDR_MASK,
2462 adj0->rewrite_header.dst_mcast_offset,
2463 &ip0->dst_address.as_u32, (u8 *) ip0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002464 }
Kingwel Xiecb36a1d2019-03-20 03:45:47 -04002465 else
2466 {
2467 b[0]->error = error_node->errors[error0];
Neale Ranns0b6a8572019-10-30 17:34:14 +00002468 /* undo the TTL decrement - we'll be back to do it again */
2469 if (error0 == IP4_ERROR_MTU_EXCEEDED)
2470 ip4_ttl_inc (b[0], ip0);
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002471 }
2472
2473 next += 1;
2474 b += 1;
2475 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476 }
2477
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002478
Ed Warnickecb9cada2015-12-08 15:45:58 -07002479 /* Need to do trace after rewrites to pick up new packet data. */
2480 if (node->flags & VLIB_NODE_FLAG_TRACE)
Neale Rannsf06aea52016-11-29 06:51:37 -08002481 ip4_forward_next_trace (vm, node, frame, VLIB_TX);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002482
Damjan Marionca3ff1a2018-08-23 09:49:46 +02002483 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002484 return frame->n_vectors;
2485}
2486
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002487always_inline uword
2488ip4_rewrite_inline (vlib_main_t * vm,
2489 vlib_node_runtime_t * node,
2490 vlib_frame_t * frame,
2491 int do_counters, int is_midchain, int is_mcast)
2492{
Mohsin Kazmi3f5594d2019-12-03 18:56:26 +01002493 return ip4_rewrite_inline_with_gso (vm, node, frame, do_counters,
2494 is_midchain, is_mcast);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02002495}
2496
Dave Barach132d51d2016-07-07 10:10:17 -04002497
Neale Rannsf06aea52016-11-29 06:51:37 -08002498/** @brief IPv4 rewrite node.
2499 @node ip4-rewrite
Dave Barach132d51d2016-07-07 10:10:17 -04002500
2501 This is the IPv4 transit-rewrite node: decrement TTL, fix the ipv4
2502 header checksum, fetch the ip adjacency, check the outbound mtu,
2503 apply the adjacency rewrite, and send pkts to the adjacency
2504 rewrite header's rewrite_next_index.
2505
2506 @param vm vlib_main_t corresponding to the current thread
2507 @param node vlib_node_runtime_t
2508 @param frame vlib_frame_t whose contents should be dispatched
2509
2510 @par Graph mechanics: buffer metadata, next index usage
2511
2512 @em Uses:
2513 - <code>vnet_buffer(b)->ip.adj_index[VLIB_TX]</code>
2514 - the rewrite adjacency index
2515 - <code>adj->lookup_next_index</code>
2516 - Must be IP_LOOKUP_NEXT_REWRITE or IP_LOOKUP_NEXT_ARP, otherwise
Dave Barach75fc8542016-10-11 16:16:02 -04002517 the packet will be dropped.
Dave Barach132d51d2016-07-07 10:10:17 -04002518 - <code>adj->rewrite_header</code>
2519 - Rewrite string length, rewrite string, next_index
2520
2521 @em Sets:
2522 - <code>b->current_data, b->current_length</code>
2523 - Updated net of applying the rewrite string
2524
2525 <em>Next Indices:</em>
2526 - <code> adj->rewrite_header.next_index </code>
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002527 or @c ip4-drop
Dave Barach132d51d2016-07-07 10:10:17 -04002528*/
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002529
2530VLIB_NODE_FN (ip4_rewrite_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
2531 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002532{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002533 if (adj_are_counters_enabled ())
2534 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2535 else
2536 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002537}
2538
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002539VLIB_NODE_FN (ip4_rewrite_bcast_node) (vlib_main_t * vm,
2540 vlib_node_runtime_t * node,
2541 vlib_frame_t * frame)
Neale Ranns1855b8e2018-07-11 10:31:26 -07002542{
2543 if (adj_are_counters_enabled ())
2544 return ip4_rewrite_inline (vm, node, frame, 1, 0, 0);
2545 else
2546 return ip4_rewrite_inline (vm, node, frame, 0, 0, 0);
2547}
2548
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002549VLIB_NODE_FN (ip4_midchain_node) (vlib_main_t * vm,
2550 vlib_node_runtime_t * node,
2551 vlib_frame_t * frame)
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002552{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002553 if (adj_are_counters_enabled ())
2554 return ip4_rewrite_inline (vm, node, frame, 1, 1, 0);
2555 else
2556 return ip4_rewrite_inline (vm, node, frame, 0, 1, 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002557}
2558
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002559VLIB_NODE_FN (ip4_rewrite_mcast_node) (vlib_main_t * vm,
2560 vlib_node_runtime_t * node,
2561 vlib_frame_t * frame)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002562{
Neale Ranns9c6a6132017-02-21 05:33:14 -08002563 if (adj_are_counters_enabled ())
2564 return ip4_rewrite_inline (vm, node, frame, 1, 0, 1);
2565 else
2566 return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
Neale Ranns32e1c012016-11-22 17:07:28 +00002567}
Ed Warnickecb9cada2015-12-08 15:45:58 -07002568
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002569VLIB_NODE_FN (ip4_mcast_midchain_node) (vlib_main_t * vm,
2570 vlib_node_runtime_t * node,
2571 vlib_frame_t * frame)
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002572{
2573 if (adj_are_counters_enabled ())
2574 return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
2575 else
2576 return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
2577}
2578
Neale Ranns32e1c012016-11-22 17:07:28 +00002579/* *INDENT-OFF* */
2580VLIB_REGISTER_NODE (ip4_rewrite_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002581 .name = "ip4-rewrite",
2582 .vector_size = sizeof (u32),
Ed Warnickecb9cada2015-12-08 15:45:58 -07002583
Neale Ranns32e1c012016-11-22 17:07:28 +00002584 .format_trace = format_ip4_rewrite_trace,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585
Ole Troan313f7e22018-04-10 16:02:51 +02002586 .n_next_nodes = IP4_REWRITE_N_NEXT,
Neale Ranns32e1c012016-11-22 17:07:28 +00002587 .next_nodes = {
Vijayabhaskar Katamreddyce074122017-11-15 13:50:26 -08002588 [IP4_REWRITE_NEXT_DROP] = "ip4-drop",
Neale Ranns32e1c012016-11-22 17:07:28 +00002589 [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
Ole Troan313f7e22018-04-10 16:02:51 +02002590 [IP4_REWRITE_NEXT_FRAGMENT] = "ip4-frag",
Neale Ranns32e1c012016-11-22 17:07:28 +00002591 },
2592};
Neale Ranns1855b8e2018-07-11 10:31:26 -07002593
2594VLIB_REGISTER_NODE (ip4_rewrite_bcast_node) = {
Neale Ranns1855b8e2018-07-11 10:31:26 -07002595 .name = "ip4-rewrite-bcast",
2596 .vector_size = sizeof (u32),
2597
2598 .format_trace = format_ip4_rewrite_trace,
2599 .sibling_of = "ip4-rewrite",
2600};
Neale Ranns32e1c012016-11-22 17:07:28 +00002601
2602VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002603 .name = "ip4-rewrite-mcast",
2604 .vector_size = sizeof (u32),
2605
2606 .format_trace = format_ip4_rewrite_trace,
2607 .sibling_of = "ip4-rewrite",
2608};
Neale Ranns32e1c012016-11-22 17:07:28 +00002609
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002610VLIB_REGISTER_NODE (ip4_mcast_midchain_node) = {
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002611 .name = "ip4-mcast-midchain",
2612 .vector_size = sizeof (u32),
2613
2614 .format_trace = format_ip4_rewrite_trace,
2615 .sibling_of = "ip4-rewrite",
2616};
Neale Ranns0f26c5a2017-03-01 15:12:11 -08002617
Neale Ranns32e1c012016-11-22 17:07:28 +00002618VLIB_REGISTER_NODE (ip4_midchain_node) = {
Neale Ranns32e1c012016-11-22 17:07:28 +00002619 .name = "ip4-midchain",
2620 .vector_size = sizeof (u32),
Neale Ranns0b6a8572019-10-30 17:34:14 +00002621 .format_trace = format_ip4_rewrite_trace,
2622 .sibling_of = "ip4-rewrite",
Neale Ranns32e1c012016-11-22 17:07:28 +00002623};
Neale Ranns32e1c012016-11-22 17:07:28 +00002624/* *INDENT-ON */
Damjan Marion1c80e832016-05-11 23:07:18 +02002625
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002626static int
Dave Barachd7cb1b52016-12-09 09:52:16 -05002627ip4_lookup_validate (ip4_address_t * a, u32 fib_index0)
2628{
2629 ip4_fib_mtrie_t *mtrie0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002630 ip4_fib_mtrie_leaf_t leaf0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002631 u32 lbi0;
Dave Barach75fc8542016-10-11 16:16:02 -04002632
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002633 mtrie0 = &ip4_fib_get (fib_index0)->mtrie;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002634
Neale Ranns04a75e32017-03-23 06:46:01 -07002635 leaf0 = ip4_fib_mtrie_lookup_step_one (mtrie0, a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002636 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 2);
2637 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, a, 3);
Dave Barach75fc8542016-10-11 16:16:02 -04002638
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002639 lbi0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
Dave Barach75fc8542016-10-11 16:16:02 -04002640
Dave Barachd7cb1b52016-12-09 09:52:16 -05002641 return lbi0 == ip4_fib_table_lookup_lb (ip4_fib_get (fib_index0), a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642}
Dave Barach75fc8542016-10-11 16:16:02 -04002643
Ed Warnickecb9cada2015-12-08 15:45:58 -07002644static clib_error_t *
2645test_lookup_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002646 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002647{
Billy McFall309fe062016-10-14 07:37:33 -04002648 ip4_fib_t *fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002649 u32 table_id = 0;
2650 f64 count = 1;
2651 u32 n;
2652 int i;
2653 ip4_address_t ip4_base_address;
2654 u64 errors = 0;
2655
Dave Barachd7cb1b52016-12-09 09:52:16 -05002656 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2657 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002658 if (unformat (input, "table %d", &table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002659 {
2660 /* Make sure the entry exists. */
2661 fib = ip4_fib_get (table_id);
2662 if ((fib) && (fib->index != table_id))
2663 return clib_error_return (0, "<fib-index> %d does not exist",
2664 table_id);
2665 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002666 else if (unformat (input, "count %f", &count))
2667 ;
2668
2669 else if (unformat (input, "%U",
2670 unformat_ip4_address, &ip4_base_address))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002671 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002672 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002673 return clib_error_return (0, "unknown input `%U'",
2674 format_unformat_error, input);
2675 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002676
2677 n = count;
2678
2679 for (i = 0; i < n; i++)
2680 {
2681 if (!ip4_lookup_validate (&ip4_base_address, table_id))
Dave Barachd7cb1b52016-12-09 09:52:16 -05002682 errors++;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002683
Dave Barach75fc8542016-10-11 16:16:02 -04002684 ip4_base_address.as_u32 =
Dave Barachd7cb1b52016-12-09 09:52:16 -05002685 clib_host_to_net_u32 (1 +
2686 clib_net_to_host_u32 (ip4_base_address.as_u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002687 }
2688
Dave Barach75fc8542016-10-11 16:16:02 -04002689 if (errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002690 vlib_cli_output (vm, "%llu errors out of %d lookups\n", errors, n);
2691 else
2692 vlib_cli_output (vm, "No errors in %d lookups\n", n);
2693
2694 return 0;
2695}
2696
Billy McFall0683c9c2016-10-13 08:27:31 -04002697/*?
2698 * Perform a lookup of an IPv4 Address (or range of addresses) in the
2699 * given FIB table to determine if there is a conflict with the
2700 * adjacency table. The fib-id can be determined by using the
2701 * '<em>show ip fib</em>' command. If fib-id is not entered, default value
2702 * of 0 is used.
2703 *
2704 * @todo This command uses fib-id, other commands use table-id (not
2705 * just a name, they are different indexes). Would like to change this
2706 * to table-id for consistency.
2707 *
2708 * @cliexpar
2709 * Example of how to run the test lookup command:
2710 * @cliexstart{test lookup 172.16.1.1 table 1 count 2}
2711 * No errors in 2 lookups
2712 * @cliexend
2713?*/
2714/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002715VLIB_CLI_COMMAND (lookup_test_command, static) =
2716{
2717 .path = "test lookup",
2718 .short_help = "test lookup <ipv4-addr> [table <fib-id>] [count <nn>]",
2719 .function = test_lookup_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002720};
Billy McFall0683c9c2016-10-13 08:27:31 -04002721/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002722
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002723#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002724int
2725vnet_set_ip4_flow_hash (u32 table_id, u32 flow_hash_config)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726{
Neale Ranns107e7d42017-04-11 09:55:19 -07002727 u32 fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002728
Neale Ranns107e7d42017-04-11 09:55:19 -07002729 fib_index = fib_table_find (FIB_PROTOCOL_IP4, table_id);
2730
2731 if (~0 == fib_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002732 return VNET_API_ERROR_NO_SUCH_FIB;
2733
Neale Ranns227038a2017-04-21 01:07:59 -07002734 fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP4,
2735 flow_hash_config);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002736
Ed Warnickecb9cada2015-12-08 15:45:58 -07002737 return 0;
2738}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002739#endif
Dave Barach75fc8542016-10-11 16:16:02 -04002740
Ed Warnickecb9cada2015-12-08 15:45:58 -07002741static clib_error_t *
2742set_ip_flow_hash_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002743 unformat_input_t * input,
2744 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745{
2746 int matched = 0;
2747 u32 table_id = 0;
2748 u32 flow_hash_config = 0;
2749 int rv;
2750
Dave Barachd7cb1b52016-12-09 09:52:16 -05002751 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2752 {
2753 if (unformat (input, "table %d", &table_id))
2754 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002755#define _(a,v) \
2756 else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
Dave Barachd7cb1b52016-12-09 09:52:16 -05002757 foreach_flow_hash_bit
Ed Warnickecb9cada2015-12-08 15:45:58 -07002758#undef _
Dave Barachd7cb1b52016-12-09 09:52:16 -05002759 else
2760 break;
2761 }
Dave Barach75fc8542016-10-11 16:16:02 -04002762
Ed Warnickecb9cada2015-12-08 15:45:58 -07002763 if (matched == 0)
2764 return clib_error_return (0, "unknown input `%U'",
Dave Barachd7cb1b52016-12-09 09:52:16 -05002765 format_unformat_error, input);
Dave Barach75fc8542016-10-11 16:16:02 -04002766
Ed Warnickecb9cada2015-12-08 15:45:58 -07002767 rv = vnet_set_ip4_flow_hash (table_id, flow_hash_config);
2768 switch (rv)
2769 {
2770 case 0:
2771 break;
Dave Barach75fc8542016-10-11 16:16:02 -04002772
Ed Warnickecb9cada2015-12-08 15:45:58 -07002773 case VNET_API_ERROR_NO_SUCH_FIB:
2774 return clib_error_return (0, "no such FIB table %d", table_id);
Dave Barach75fc8542016-10-11 16:16:02 -04002775
Ed Warnickecb9cada2015-12-08 15:45:58 -07002776 default:
2777 clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2778 break;
2779 }
Dave Barach75fc8542016-10-11 16:16:02 -04002780
Ed Warnickecb9cada2015-12-08 15:45:58 -07002781 return 0;
2782}
Dave Barach75fc8542016-10-11 16:16:02 -04002783
Billy McFall0683c9c2016-10-13 08:27:31 -04002784/*?
2785 * Configure the set of IPv4 fields used by the flow hash.
2786 *
2787 * @cliexpar
2788 * Example of how to set the flow hash on a given table:
2789 * @cliexcmd{set ip flow-hash table 7 dst sport dport proto}
2790 * Example of display the configured flow hash:
2791 * @cliexstart{show ip fib}
Billy McFallebb9a6a2016-10-17 11:35:32 -04002792 * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2793 * 0.0.0.0/0
2794 * unicast-ip4-chain
2795 * [@0]: dpo-load-balance: [index:0 buckets:1 uRPF:0 to:[0:0]]
2796 * [0] [@0]: dpo-drop ip6
2797 * 0.0.0.0/32
2798 * unicast-ip4-chain
2799 * [@0]: dpo-load-balance: [index:1 buckets:1 uRPF:1 to:[0:0]]
2800 * [0] [@0]: dpo-drop ip6
2801 * 224.0.0.0/8
2802 * unicast-ip4-chain
2803 * [@0]: dpo-load-balance: [index:3 buckets:1 uRPF:3 to:[0:0]]
2804 * [0] [@0]: dpo-drop ip6
2805 * 6.0.1.2/32
2806 * unicast-ip4-chain
2807 * [@0]: dpo-load-balance: [index:30 buckets:1 uRPF:29 to:[0:0]]
2808 * [0] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2809 * 7.0.0.1/32
2810 * unicast-ip4-chain
2811 * [@0]: dpo-load-balance: [index:31 buckets:4 uRPF:30 to:[0:0]]
2812 * [0] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2813 * [1] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2814 * [2] [@3]: arp-ipv4: via 6.0.0.2 af_packet0
2815 * [3] [@3]: arp-ipv4: via 6.0.0.1 af_packet0
2816 * 240.0.0.0/8
2817 * unicast-ip4-chain
2818 * [@0]: dpo-load-balance: [index:2 buckets:1 uRPF:2 to:[0:0]]
2819 * [0] [@0]: dpo-drop ip6
2820 * 255.255.255.255/32
2821 * unicast-ip4-chain
2822 * [@0]: dpo-load-balance: [index:4 buckets:1 uRPF:4 to:[0:0]]
2823 * [0] [@0]: dpo-drop ip6
2824 * ipv4-VRF:7, fib_index 1, flow hash: dst sport dport proto
2825 * 0.0.0.0/0
2826 * unicast-ip4-chain
2827 * [@0]: dpo-load-balance: [index:12 buckets:1 uRPF:11 to:[0:0]]
2828 * [0] [@0]: dpo-drop ip6
2829 * 0.0.0.0/32
2830 * unicast-ip4-chain
2831 * [@0]: dpo-load-balance: [index:13 buckets:1 uRPF:12 to:[0:0]]
2832 * [0] [@0]: dpo-drop ip6
2833 * 172.16.1.0/24
2834 * unicast-ip4-chain
2835 * [@0]: dpo-load-balance: [index:17 buckets:1 uRPF:16 to:[0:0]]
2836 * [0] [@4]: ipv4-glean: af_packet0
2837 * 172.16.1.1/32
2838 * unicast-ip4-chain
2839 * [@0]: dpo-load-balance: [index:18 buckets:1 uRPF:17 to:[1:84]]
2840 * [0] [@2]: dpo-receive: 172.16.1.1 on af_packet0
2841 * 172.16.1.2/32
2842 * unicast-ip4-chain
2843 * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2844 * [0] [@5]: ipv4 via 172.16.1.2 af_packet0: IP4: 02:fe:9e:70:7a:2b -> 26:a5:f6:9c:3a:36
2845 * 172.16.2.0/24
2846 * unicast-ip4-chain
2847 * [@0]: dpo-load-balance: [index:19 buckets:1 uRPF:18 to:[0:0]]
2848 * [0] [@4]: ipv4-glean: af_packet1
2849 * 172.16.2.1/32
2850 * unicast-ip4-chain
2851 * [@0]: dpo-load-balance: [index:20 buckets:1 uRPF:19 to:[0:0]]
2852 * [0] [@2]: dpo-receive: 172.16.2.1 on af_packet1
2853 * 224.0.0.0/8
2854 * unicast-ip4-chain
2855 * [@0]: dpo-load-balance: [index:15 buckets:1 uRPF:14 to:[0:0]]
2856 * [0] [@0]: dpo-drop ip6
2857 * 240.0.0.0/8
2858 * unicast-ip4-chain
2859 * [@0]: dpo-load-balance: [index:14 buckets:1 uRPF:13 to:[0:0]]
2860 * [0] [@0]: dpo-drop ip6
2861 * 255.255.255.255/32
2862 * unicast-ip4-chain
2863 * [@0]: dpo-load-balance: [index:16 buckets:1 uRPF:15 to:[0:0]]
2864 * [0] [@0]: dpo-drop ip6
Billy McFall0683c9c2016-10-13 08:27:31 -04002865 * @cliexend
2866?*/
2867/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002868VLIB_CLI_COMMAND (set_ip_flow_hash_command, static) =
2869{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002870 .path = "set ip flow-hash",
Dave Barach75fc8542016-10-11 16:16:02 -04002871 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002872 "set ip flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002873 .function = set_ip_flow_hash_command_fn,
2874};
Billy McFall0683c9c2016-10-13 08:27:31 -04002875/* *INDENT-ON* */
Dave Barach75fc8542016-10-11 16:16:02 -04002876
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002877#ifndef CLIB_MARCH_VARIANT
Dave Barachd7cb1b52016-12-09 09:52:16 -05002878int
2879vnet_set_ip4_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2880 u32 table_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002881{
Dave Barachd7cb1b52016-12-09 09:52:16 -05002882 vnet_main_t *vnm = vnet_get_main ();
2883 vnet_interface_main_t *im = &vnm->interface_main;
2884 ip4_main_t *ipm = &ip4_main;
2885 ip_lookup_main_t *lm = &ipm->lookup_main;
2886 vnet_classify_main_t *cm = &vnet_classify_main;
Neale Rannsdf089a82016-10-02 16:39:06 +01002887 ip4_address_t *if_addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002888
2889 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2890 return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2891
2892 if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2893 return VNET_API_ERROR_NO_SUCH_ENTRY;
2894
2895 vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
Dave Barachd7cb1b52016-12-09 09:52:16 -05002896 lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002897
Neale Rannsdf089a82016-10-02 16:39:06 +01002898 if_addr = ip4_interface_first_address (ipm, sw_if_index, NULL);
2899
2900 if (NULL != if_addr)
Dave Barachd7cb1b52016-12-09 09:52:16 -05002901 {
Neale Rannsdf089a82016-10-02 16:39:06 +01002902 fib_prefix_t pfx = {
Dave Barachd7cb1b52016-12-09 09:52:16 -05002903 .fp_len = 32,
2904 .fp_proto = FIB_PROTOCOL_IP4,
2905 .fp_addr.ip4 = *if_addr,
Neale Rannsdf089a82016-10-02 16:39:06 +01002906 };
2907 u32 fib_index;
2908
Dave Barachd7cb1b52016-12-09 09:52:16 -05002909 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2910 sw_if_index);
Neale Rannsdf089a82016-10-02 16:39:06 +01002911
2912
Dave Barachd7cb1b52016-12-09 09:52:16 -05002913 if (table_index != (u32) ~ 0)
2914 {
2915 dpo_id_t dpo = DPO_INVALID;
Neale Rannsdf089a82016-10-02 16:39:06 +01002916
Dave Barachd7cb1b52016-12-09 09:52:16 -05002917 dpo_set (&dpo,
2918 DPO_CLASSIFY,
2919 DPO_PROTO_IP4,
2920 classify_dpo_create (DPO_PROTO_IP4, table_index));
Neale Rannsdf089a82016-10-02 16:39:06 +01002921
Dave Barachd7cb1b52016-12-09 09:52:16 -05002922 fib_table_entry_special_dpo_add (fib_index,
2923 &pfx,
2924 FIB_SOURCE_CLASSIFY,
2925 FIB_ENTRY_FLAG_NONE, &dpo);
2926 dpo_reset (&dpo);
2927 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002928 else
Dave Barachd7cb1b52016-12-09 09:52:16 -05002929 {
2930 fib_table_entry_special_remove (fib_index,
2931 &pfx, FIB_SOURCE_CLASSIFY);
2932 }
2933 }
Neale Rannsdf089a82016-10-02 16:39:06 +01002934
Ed Warnickecb9cada2015-12-08 15:45:58 -07002935 return 0;
2936}
Damjan Marionc9dad5d2018-08-11 22:10:29 +02002937#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07002938
2939static clib_error_t *
2940set_ip_classify_command_fn (vlib_main_t * vm,
Dave Barachd7cb1b52016-12-09 09:52:16 -05002941 unformat_input_t * input,
2942 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002943{
2944 u32 table_index = ~0;
2945 int table_index_set = 0;
2946 u32 sw_if_index = ~0;
2947 int rv;
Dave Barach75fc8542016-10-11 16:16:02 -04002948
Dave Barachd7cb1b52016-12-09 09:52:16 -05002949 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2950 {
2951 if (unformat (input, "table-index %d", &table_index))
2952 table_index_set = 1;
2953 else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2954 vnet_get_main (), &sw_if_index))
2955 ;
2956 else
2957 break;
2958 }
Dave Barach75fc8542016-10-11 16:16:02 -04002959
Ed Warnickecb9cada2015-12-08 15:45:58 -07002960 if (table_index_set == 0)
2961 return clib_error_return (0, "classify table-index must be specified");
2962
2963 if (sw_if_index == ~0)
2964 return clib_error_return (0, "interface / subif must be specified");
2965
2966 rv = vnet_set_ip4_classify_intfc (vm, sw_if_index, table_index);
2967
2968 switch (rv)
2969 {
2970 case 0:
2971 break;
2972
2973 case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2974 return clib_error_return (0, "No such interface");
2975
2976 case VNET_API_ERROR_NO_SUCH_ENTRY:
2977 return clib_error_return (0, "No such classifier table");
2978 }
2979 return 0;
2980}
2981
Billy McFall0683c9c2016-10-13 08:27:31 -04002982/*?
2983 * Assign a classification table to an interface. The classification
2984 * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
2985 * commands. Once the table is create, use this command to filter packets
2986 * on an interface.
2987 *
2988 * @cliexpar
2989 * Example of how to assign a classification table to an interface:
2990 * @cliexcmd{set ip classify intfc GigabitEthernet2/0/0 table-index 1}
2991?*/
2992/* *INDENT-OFF* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05002993VLIB_CLI_COMMAND (set_ip_classify_command, static) =
2994{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002995 .path = "set ip classify",
Dave Barach75fc8542016-10-11 16:16:02 -04002996 .short_help =
Billy McFall0683c9c2016-10-13 08:27:31 -04002997 "set ip classify intfc <interface> table-index <classify-idx>",
Ed Warnickecb9cada2015-12-08 15:45:58 -07002998 .function = set_ip_classify_command_fn,
2999};
Billy McFall0683c9c2016-10-13 08:27:31 -04003000/* *INDENT-ON* */
Dave Barachd7cb1b52016-12-09 09:52:16 -05003001
Neale Ranns1ec36522017-11-29 05:20:37 -08003002static clib_error_t *
3003ip4_config (vlib_main_t * vm, unformat_input_t * input)
3004{
3005 ip4_main_t *im = &ip4_main;
3006 uword heapsize = 0;
3007
3008 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3009 {
3010 if (unformat (input, "heap-size %U", unformat_memory_size, &heapsize))
3011 ;
3012 else
3013 return clib_error_return (0,
3014 "invalid heap-size parameter `%U'",
3015 format_unformat_error, input);
3016 }
3017
3018 im->mtrie_heap_size = heapsize;
3019
3020 return 0;
3021}
3022
3023VLIB_EARLY_CONFIG_FUNCTION (ip4_config, "ip");
3024
Dave Barachd7cb1b52016-12-09 09:52:16 -05003025/*
3026 * fd.io coding-style-patch-verification: ON
3027 *
3028 * Local Variables:
3029 * eval: (c-set-style "gnu")
3030 * End:
3031 */